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