kind 3.0.1 → 5.1.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 +42 -12
- data/.travis.yml +7 -5
- data/CHANGELOG.md +1309 -0
- data/Gemfile +22 -7
- data/README.md +990 -490
- data/kind.gemspec +1 -1
- data/lib/kind.rb +29 -292
- data/lib/kind/active_model/validation.rb +3 -4
- data/lib/kind/core.rb +15 -0
- data/lib/kind/core/dig.rb +40 -0
- data/lib/kind/core/empty.rb +13 -0
- data/lib/kind/core/empty/constant.rb +7 -0
- data/lib/kind/{error.rb → core/error.rb} +2 -6
- data/lib/kind/core/maybe.rb +42 -0
- data/lib/kind/core/maybe/none.rb +57 -0
- data/lib/kind/core/maybe/result.rb +51 -0
- data/lib/kind/core/maybe/some.rb +90 -0
- data/lib/kind/core/maybe/typed.rb +29 -0
- data/lib/kind/core/maybe/wrappable.rb +33 -0
- data/lib/kind/core/presence.rb +33 -0
- data/lib/kind/core/try.rb +34 -0
- data/lib/kind/core/type_checker.rb +87 -0
- data/lib/kind/core/type_checkers.rb +30 -0
- data/lib/kind/core/type_checkers/custom/boolean.rb +19 -0
- data/lib/kind/core/type_checkers/custom/callable.rb +19 -0
- data/lib/kind/core/type_checkers/custom/lambda.rb +19 -0
- data/lib/kind/core/type_checkers/ruby/array.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/class.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/comparable.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/enumerable.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/enumerator.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/file.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/float.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/hash.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/integer.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/io.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/method.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/module.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/numeric.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/proc.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/queue.rb +14 -0
- data/lib/kind/core/type_checkers/ruby/range.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/regexp.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/string.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/struct.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/symbol.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/time.rb +13 -0
- data/lib/kind/core/type_checkers/stdlib/open_struct.rb +13 -0
- data/lib/kind/core/type_checkers/stdlib/set.rb +17 -0
- data/lib/kind/{undefined.rb → core/undefined.rb} +4 -2
- data/lib/kind/core/utils/kind.rb +61 -0
- data/lib/kind/core/utils/undefined.rb +7 -0
- data/lib/kind/validator.rb +108 -1
- data/lib/kind/version.rb +1 -1
- data/test.sh +4 -4
- metadata +50 -15
- 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/empty.rb +0 -21
- data/lib/kind/is.rb +0 -19
- data/lib/kind/maybe.rb +0 -183
- data/lib/kind/of.rb +0 -11
- data/lib/kind/types.rb +0 -115
data/lib/kind/checker/factory.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'singleton'
|
4
|
-
|
5
|
-
module Kind
|
6
|
-
class Checker
|
7
|
-
class Factory
|
8
|
-
include Singleton
|
9
|
-
|
10
|
-
def self.create(kind)
|
11
|
-
instance.create(kind)
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@__checkers__ = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
MODULE_OR_CLASS = 'Module/Class'.freeze
|
19
|
-
|
20
|
-
private_constant :MODULE_OR_CLASS
|
21
|
-
|
22
|
-
def create(kind)
|
23
|
-
@__checkers__[kind] ||= begin
|
24
|
-
kind_name = kind.name
|
25
|
-
|
26
|
-
if Kind::Of.const_defined?(kind_name, false)
|
27
|
-
Kind::Of.const_get(kind_name)
|
28
|
-
else
|
29
|
-
Kind::Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kind
|
4
|
-
class Checker
|
5
|
-
module Protocol
|
6
|
-
def class?(value)
|
7
|
-
Kind::Is.__call__(__kind, value)
|
8
|
-
end
|
9
|
-
|
10
|
-
def instance(value, options = Empty::HASH)
|
11
|
-
default = options[:or]
|
12
|
-
|
13
|
-
return Kind::Of.(__kind, value) if ::Kind::Maybe::Value.none?(default)
|
14
|
-
|
15
|
-
Kind::Undefined != value && instance?(value) ? value : Kind::Of.(__kind, default)
|
16
|
-
end
|
17
|
-
|
18
|
-
def [](value, options = options = Empty::HASH)
|
19
|
-
instance(value, options)
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_proc
|
23
|
-
@to_proc ||=
|
24
|
-
-> checker { -> value { checker.instance(value) } }.call(self)
|
25
|
-
end
|
26
|
-
|
27
|
-
def __is_instance__(value)
|
28
|
-
value.kind_of?(__kind)
|
29
|
-
end
|
30
|
-
|
31
|
-
def is_instance_to_proc
|
32
|
-
@is_instance_to_proc ||=
|
33
|
-
-> checker { -> value { checker.__is_instance__(value) } }.call(self)
|
34
|
-
end
|
35
|
-
|
36
|
-
def instance?(*args)
|
37
|
-
return is_instance_to_proc if args.empty?
|
38
|
-
|
39
|
-
return args.all? { |object| __is_instance__(object) } if args.size > 1
|
40
|
-
|
41
|
-
arg = args[0]
|
42
|
-
Kind::Undefined == arg ? is_instance_to_proc : __is_instance__(arg)
|
43
|
-
end
|
44
|
-
|
45
|
-
def or_nil(value)
|
46
|
-
return value if instance?(value)
|
47
|
-
end
|
48
|
-
|
49
|
-
def or_undefined(value)
|
50
|
-
or_nil(value) || Kind::Undefined
|
51
|
-
end
|
52
|
-
|
53
|
-
def __as_maybe__(value)
|
54
|
-
Kind::Maybe.new(or_nil(value))
|
55
|
-
end
|
56
|
-
|
57
|
-
def as_maybe_to_proc
|
58
|
-
@as_maybe_to_proc ||=
|
59
|
-
-> checker { -> value { checker.__as_maybe__(value) } }.call(self)
|
60
|
-
end
|
61
|
-
|
62
|
-
def as_maybe(value = Kind::Undefined)
|
63
|
-
return __as_maybe__(value) if Kind::Undefined != value
|
64
|
-
|
65
|
-
as_maybe_to_proc
|
66
|
-
end
|
67
|
-
|
68
|
-
def as_optional(value = Kind::Undefined)
|
69
|
-
as_maybe(value)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/kind/empty.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'set'
|
4
|
-
|
5
|
-
module Kind
|
6
|
-
module Empty
|
7
|
-
SET = ::Set.new.freeze
|
8
|
-
|
9
|
-
HASH = {}.freeze
|
10
|
-
|
11
|
-
ARY = [].freeze
|
12
|
-
ARRAY = ARY
|
13
|
-
|
14
|
-
STR = ''.freeze
|
15
|
-
STRING = STR
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
unless defined?(Empty)
|
20
|
-
Empty = Kind::Empty
|
21
|
-
end
|
data/lib/kind/is.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kind
|
4
|
-
module Is
|
5
|
-
def self.call(expected, object)
|
6
|
-
__call__(Kind::Of.Module(expected), object)
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.__call__(expected_kind, object)
|
10
|
-
kind = Kind::Of.Module(object)
|
11
|
-
|
12
|
-
if kind.is_a?(Class)
|
13
|
-
kind <= expected_kind || false
|
14
|
-
else
|
15
|
-
kind == expected_kind || kind.is_a?(expected_kind)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/kind/maybe.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kind
|
4
|
-
module Maybe
|
5
|
-
class Typed
|
6
|
-
def initialize(kind)
|
7
|
-
@kind_checker = Kind::Checker::Factory.create(kind)
|
8
|
-
end
|
9
|
-
|
10
|
-
def wrap(value)
|
11
|
-
@kind_checker.as_maybe(value)
|
12
|
-
end
|
13
|
-
|
14
|
-
alias_method :new, :wrap
|
15
|
-
alias_method :[], :wrap
|
16
|
-
end
|
17
|
-
|
18
|
-
module Value
|
19
|
-
def self.none?(value)
|
20
|
-
value.nil? || Undefined == value
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.some?(value)
|
24
|
-
!none?(value)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Result
|
29
|
-
attr_reader :value
|
30
|
-
|
31
|
-
def initialize(value)
|
32
|
-
@value = value.kind_of?(Result) ? value.value : value
|
33
|
-
end
|
34
|
-
|
35
|
-
def value_or(method_name = Undefined, &block)
|
36
|
-
raise NotImplementedError
|
37
|
-
end
|
38
|
-
|
39
|
-
def none?
|
40
|
-
raise NotImplementedError
|
41
|
-
end
|
42
|
-
|
43
|
-
def some?; !none?; end
|
44
|
-
|
45
|
-
def map(&fn)
|
46
|
-
raise NotImplementedError
|
47
|
-
end
|
48
|
-
|
49
|
-
def try(method_name = Undefined, &block)
|
50
|
-
raise NotImplementedError
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class None < Result
|
55
|
-
INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
|
56
|
-
|
57
|
-
def value_or(default = Undefined, &block)
|
58
|
-
raise ArgumentError, INVALID_DEFAULT_ARG if Undefined == default && !block
|
59
|
-
|
60
|
-
Undefined != default ? default : block.call
|
61
|
-
end
|
62
|
-
|
63
|
-
def none?; true; end
|
64
|
-
|
65
|
-
def map(&fn)
|
66
|
-
self
|
67
|
-
end
|
68
|
-
|
69
|
-
alias_method :then, :map
|
70
|
-
|
71
|
-
def try!(method_name = Undefined, *args, &block)
|
72
|
-
Kind.of.Symbol(method_name) if Undefined != method_name
|
73
|
-
|
74
|
-
NONE_WITH_NIL_VALUE
|
75
|
-
end
|
76
|
-
|
77
|
-
alias_method :try, :try!
|
78
|
-
|
79
|
-
private_constant :INVALID_DEFAULT_ARG
|
80
|
-
end
|
81
|
-
|
82
|
-
NONE_WITH_NIL_VALUE = None.new(nil)
|
83
|
-
NONE_WITH_UNDEFINED_VALUE = None.new(Undefined)
|
84
|
-
|
85
|
-
private_constant :NONE_WITH_NIL_VALUE, :NONE_WITH_UNDEFINED_VALUE
|
86
|
-
|
87
|
-
class Some < Result
|
88
|
-
def value_or(default = Undefined, &block)
|
89
|
-
@value
|
90
|
-
end
|
91
|
-
|
92
|
-
def none?; false; end
|
93
|
-
|
94
|
-
def map(&fn)
|
95
|
-
result = fn.call(@value)
|
96
|
-
|
97
|
-
resolve(result)
|
98
|
-
end
|
99
|
-
|
100
|
-
alias_method :then, :map
|
101
|
-
|
102
|
-
def try!(method_name = Undefined, *args, &block)
|
103
|
-
Kind::Of::Symbol(method_name) if Undefined != method_name
|
104
|
-
|
105
|
-
__try__(method_name, args, block)
|
106
|
-
end
|
107
|
-
|
108
|
-
def try(method_name = Undefined, *args, &block)
|
109
|
-
if (Undefined != method_name && value.respond_to?(Kind::Of::Symbol(method_name))) ||
|
110
|
-
(Undefined == method_name && block)
|
111
|
-
__try__(method_name, args, block)
|
112
|
-
else
|
113
|
-
NONE_WITH_NIL_VALUE
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def __try__(method_name = Undefined, args, block)
|
120
|
-
fn = Undefined == method_name ? block : method_name.to_proc
|
121
|
-
|
122
|
-
result = args.empty? ? fn.call(value) : fn.call(*args.unshift(value))
|
123
|
-
|
124
|
-
resolve(result)
|
125
|
-
end
|
126
|
-
|
127
|
-
def resolve(result)
|
128
|
-
return result if Maybe::None === result
|
129
|
-
return NONE_WITH_NIL_VALUE if result.nil?
|
130
|
-
return NONE_WITH_UNDEFINED_VALUE if Undefined == result
|
131
|
-
|
132
|
-
Some.new(result)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def self.new(value)
|
137
|
-
result_type = Maybe::Value.none?(value) ? None : Some
|
138
|
-
result_type.new(value)
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.[](value)
|
142
|
-
new(value)
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.wrap(value)
|
146
|
-
new(value)
|
147
|
-
end
|
148
|
-
|
149
|
-
def self.none
|
150
|
-
NONE_WITH_NIL_VALUE
|
151
|
-
end
|
152
|
-
|
153
|
-
VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
|
154
|
-
|
155
|
-
private_constant :VALUE_CANT_BE_NONE
|
156
|
-
|
157
|
-
def self.some(value)
|
158
|
-
return Maybe::Some.new(value) if Value.some?(value)
|
159
|
-
|
160
|
-
raise ArgumentError, VALUE_CANT_BE_NONE
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
Optional = Maybe
|
165
|
-
|
166
|
-
None = Maybe.none
|
167
|
-
|
168
|
-
def self.None
|
169
|
-
Kind::None
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.Some(value)
|
173
|
-
Maybe.some(value)
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.Maybe(kind)
|
177
|
-
Maybe::Typed.new(kind)
|
178
|
-
end
|
179
|
-
|
180
|
-
def self.Optional(kind)
|
181
|
-
Maybe::Typed.new(kind)
|
182
|
-
end
|
183
|
-
end
|
data/lib/kind/of.rb
DELETED
data/lib/kind/types.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kind
|
4
|
-
module Types
|
5
|
-
extend self
|
6
|
-
|
7
|
-
COLONS = '::'.freeze
|
8
|
-
|
9
|
-
KIND_OF = <<-RUBY
|
10
|
-
def self.%{method_name}(object = Undefined, options = Empty::HASH)
|
11
|
-
default = options[:or]
|
12
|
-
|
13
|
-
return Kind::Of::%{kind_name} if Undefined == object && default.nil?
|
14
|
-
|
15
|
-
is_instance = Kind::Of::%{kind_name}.__is_instance__(object)
|
16
|
-
|
17
|
-
return object if is_instance
|
18
|
-
|
19
|
-
Kind::Of.(::%{kind_name_to_check}, object && default ? default : object || default)
|
20
|
-
end
|
21
|
-
RUBY
|
22
|
-
|
23
|
-
KIND_OF_IS = <<-RUBY
|
24
|
-
def self.%{method_name}?(*args)
|
25
|
-
Kind::Of::%{kind_name}.instance?(*args)
|
26
|
-
end
|
27
|
-
RUBY
|
28
|
-
|
29
|
-
KIND_IS = <<-RUBY
|
30
|
-
def self.%{method_name}(value = Undefined)
|
31
|
-
return Kind::Is::%{kind_name} if Undefined == value
|
32
|
-
|
33
|
-
Kind::Is.__call__(::%{kind_name_to_check}, value)
|
34
|
-
end
|
35
|
-
RUBY
|
36
|
-
|
37
|
-
private_constant :KIND_OF, :KIND_IS, :COLONS
|
38
|
-
|
39
|
-
def add(kind, name: nil)
|
40
|
-
kind_name = Kind.of.Module(kind).name
|
41
|
-
checker = name ? Kind::Of.(String, name) : kind_name
|
42
|
-
|
43
|
-
if checker.include?(COLONS)
|
44
|
-
add_kind_with_namespace(checker, method_name: name)
|
45
|
-
else
|
46
|
-
add_root(checker, kind_name, method_name: name,
|
47
|
-
kind_name_to_check: kind_name,
|
48
|
-
create_kind_is_mod: false)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def add_root(checker, kind_name, method_name:, create_kind_is_mod:, kind_name_to_check: nil)
|
55
|
-
root_kind_name = method_name ? method_name : kind_name
|
56
|
-
|
57
|
-
params = {
|
58
|
-
method_name: method_name ? method_name : checker,
|
59
|
-
kind_name: method_name ? method_name : kind_name,
|
60
|
-
kind_name_to_check: kind_name_to_check || root_kind_name
|
61
|
-
}
|
62
|
-
|
63
|
-
add_kind(params, Kind::Of, Kind::Is, create_kind_is_mod)
|
64
|
-
end
|
65
|
-
|
66
|
-
def add_kind_with_namespace(checker, method_name:)
|
67
|
-
raise NotImplementedError if method_name
|
68
|
-
|
69
|
-
const_names = checker.split(COLONS)
|
70
|
-
const_names.each_with_index do |const_name, index|
|
71
|
-
if index == 0
|
72
|
-
add_root(const_name, const_name, method_name: nil, create_kind_is_mod: true)
|
73
|
-
else
|
74
|
-
add_node(const_names, index)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def add_node(const_names, index)
|
80
|
-
namespace = const_names[0..(index-1)]
|
81
|
-
namespace_name = namespace.join(COLONS)
|
82
|
-
|
83
|
-
kind_of_mod = Kind::Of.const_get(namespace_name)
|
84
|
-
kind_is_mod = Kind::Is.const_get(namespace_name)
|
85
|
-
|
86
|
-
checker = const_names[index]
|
87
|
-
kind_name = const_names[0..index].join(COLONS)
|
88
|
-
|
89
|
-
params = { method_name: checker, kind_name: kind_name }
|
90
|
-
|
91
|
-
add_kind(params, kind_of_mod, kind_is_mod, true)
|
92
|
-
end
|
93
|
-
|
94
|
-
def add_kind(params, kind_of_mod, kind_is_mod, create_kind_is_mod)
|
95
|
-
method_name = params[:method_name]
|
96
|
-
|
97
|
-
unless kind_of_mod.respond_to?(method_name)
|
98
|
-
kind_name = params[:kind_name]
|
99
|
-
params[:kind_name_to_check] ||= kind_name
|
100
|
-
|
101
|
-
kind_checker = ::Module.new { extend Checker::Protocol }
|
102
|
-
kind_checker.module_eval("def self.__kind; #{params[:kind_name_to_check]}; end")
|
103
|
-
|
104
|
-
kind_of_mod.instance_eval(KIND_OF % params)
|
105
|
-
kind_of_mod.const_set(method_name, kind_checker)
|
106
|
-
kind_of_mod.instance_eval(KIND_OF_IS % params)
|
107
|
-
end
|
108
|
-
|
109
|
-
unless kind_is_mod.respond_to?(method_name)
|
110
|
-
kind_is_mod.instance_eval(KIND_IS % params)
|
111
|
-
kind_is_mod.const_set(method_name, Module.new) if create_kind_is_mod
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|