kind 3.1.0 → 4.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +37 -12
  4. data/.travis.yml +6 -3
  5. data/CHANGELOG.md +1230 -0
  6. data/Gemfile +10 -2
  7. data/README.md +817 -487
  8. data/lib/kind.rb +53 -283
  9. data/lib/kind/active_model/kind_validator.rb +7 -7
  10. data/lib/kind/core.rb +9 -0
  11. data/lib/kind/core/deprecation.rb +29 -0
  12. data/lib/kind/core/kind.rb +61 -0
  13. data/lib/kind/core/undefined.rb +7 -0
  14. data/lib/kind/deprecations/built_in_type_checkers.rb +23 -0
  15. data/lib/kind/{checker.rb → deprecations/checker.rb} +3 -2
  16. data/lib/kind/{checker → deprecations/checker}/factory.rb +1 -5
  17. data/lib/kind/{checker → deprecations/checker}/protocol.rb +3 -3
  18. data/lib/kind/deprecations/is.rb +35 -0
  19. data/lib/kind/deprecations/of.rb +258 -0
  20. data/lib/kind/{types.rb → deprecations/types.rb} +14 -8
  21. data/lib/kind/dig.rb +13 -9
  22. data/lib/kind/empty.rb +5 -11
  23. data/lib/kind/error.rb +2 -6
  24. data/lib/kind/maybe.rb +12 -161
  25. data/lib/kind/maybe/none.rb +57 -0
  26. data/lib/kind/maybe/result.rb +51 -0
  27. data/lib/kind/maybe/some.rb +90 -0
  28. data/lib/kind/maybe/typed.rb +29 -0
  29. data/lib/kind/maybe/wrappable.rb +35 -0
  30. data/lib/kind/presence.rb +33 -0
  31. data/lib/kind/try.rb +36 -0
  32. data/lib/kind/type_checker.rb +73 -0
  33. data/lib/kind/type_checkers.rb +30 -0
  34. data/lib/kind/type_checkers/core/array.rb +17 -0
  35. data/lib/kind/type_checkers/core/class.rb +13 -0
  36. data/lib/kind/type_checkers/core/comparable.rb +13 -0
  37. data/lib/kind/type_checkers/core/enumerable.rb +13 -0
  38. data/lib/kind/type_checkers/core/enumerator.rb +13 -0
  39. data/lib/kind/type_checkers/core/file.rb +13 -0
  40. data/lib/kind/type_checkers/core/float.rb +13 -0
  41. data/lib/kind/type_checkers/core/hash.rb +17 -0
  42. data/lib/kind/type_checkers/core/integer.rb +13 -0
  43. data/lib/kind/type_checkers/core/io.rb +13 -0
  44. data/lib/kind/type_checkers/core/method.rb +13 -0
  45. data/lib/kind/type_checkers/core/module.rb +17 -0
  46. data/lib/kind/type_checkers/core/numeric.rb +13 -0
  47. data/lib/kind/type_checkers/core/proc.rb +13 -0
  48. data/lib/kind/type_checkers/core/queue.rb +14 -0
  49. data/lib/kind/type_checkers/core/range.rb +13 -0
  50. data/lib/kind/type_checkers/core/regexp.rb +13 -0
  51. data/lib/kind/type_checkers/core/string.rb +17 -0
  52. data/lib/kind/type_checkers/core/struct.rb +13 -0
  53. data/lib/kind/type_checkers/core/symbol.rb +13 -0
  54. data/lib/kind/type_checkers/core/time.rb +13 -0
  55. data/lib/kind/type_checkers/custom/boolean.rb +19 -0
  56. data/lib/kind/type_checkers/custom/callable.rb +19 -0
  57. data/lib/kind/type_checkers/custom/lambda.rb +19 -0
  58. data/lib/kind/type_checkers/stdlib/open_struct.rb +13 -0
  59. data/lib/kind/type_checkers/stdlib/set.rb +17 -0
  60. data/lib/kind/undefined.rb +4 -2
  61. data/lib/kind/validator.rb +1 -1
  62. data/lib/kind/version.rb +1 -1
  63. data/test.sh +4 -4
  64. metadata +51 -9
  65. data/lib/kind/is.rb +0 -19
  66. data/lib/kind/of.rb +0 -11
data/lib/kind/dig.rb CHANGED
@@ -5,31 +5,35 @@ module Kind
5
5
  extend self
6
6
 
7
7
  def call(data, keys)
8
- return unless keys.is_a?(Array)
8
+ return unless keys.is_a?(::Array)
9
9
 
10
10
  keys.reduce(data) do |memo, key|
11
11
  value = get(memo, key)
12
12
 
13
- break if value.nil?
13
+ break if KIND.null?(value)
14
14
 
15
15
  value
16
16
  end
17
17
  end
18
18
 
19
+ def [](*keys)
20
+ ->(data) { call(data, keys) }
21
+ end
22
+
19
23
  private
20
24
 
21
25
  def get(data, key)
22
- return data[key] if Hash === data
26
+ return data[key] if ::Hash === data
23
27
 
24
28
  case data
25
- when Array
29
+ when ::Array
26
30
  data[key] if key.respond_to?(:to_int)
27
- when OpenStruct
31
+ when ::OpenStruct
28
32
  data[key] if key.respond_to?(:to_sym)
29
- when Struct
30
- if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
31
- data[key] rescue nil
32
- end
33
+ when ::Struct
34
+ data[key] rescue nil if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
35
+ else
36
+ data.public_send(key) if key.respond_to?(:to_sym) && data.respond_to?(key)
33
37
  end
34
38
  end
35
39
  end
data/lib/kind/empty.rb CHANGED
@@ -1,21 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
-
5
3
  module Kind
6
4
  module Empty
7
5
  SET = ::Set.new.freeze
8
-
9
6
  HASH = {}.freeze
7
+ ARRAY = [].freeze
8
+ STRING = ''.freeze
10
9
 
11
- ARY = [].freeze
12
- ARRAY = ARY
13
-
14
- STR = ''.freeze
15
- STRING = STR
10
+ ARY = ARRAY
11
+ STR = STRING
16
12
  end
17
13
  end
18
14
 
19
- unless defined?(Empty)
20
- Empty = Kind::Empty
21
- end
15
+ Empty = Kind::Empty unless defined?(Empty)
data/lib/kind/error.rb CHANGED
@@ -2,12 +2,8 @@
2
2
 
3
3
  module Kind
4
4
  class Error < TypeError
5
- UNDEFINED_OBJECT = Object.new
6
-
7
- private_constant :UNDEFINED_OBJECT
8
-
9
- def initialize(arg, object = UNDEFINED_OBJECT)
10
- if UNDEFINED_OBJECT == object
5
+ def initialize(arg, object = UNDEFINED)
6
+ if UNDEFINED == object
11
7
  # Will be used when the exception was raised with a message. e.g:
12
8
  # raise Kind::Error, "some message"
13
9
  super(arg)
data/lib/kind/maybe.rb CHANGED
@@ -4,171 +4,22 @@ require 'kind/dig'
4
4
 
5
5
  module Kind
6
6
  module Maybe
7
- class Typed
8
- def initialize(kind)
9
- @kind_checker = Kind::Checker::Factory.create(kind)
10
- end
7
+ extend self
11
8
 
12
- def wrap(value)
13
- @kind_checker.as_maybe(value)
14
- end
9
+ require 'kind/maybe/result'
10
+ require 'kind/maybe/none'
11
+ require 'kind/maybe/some'
12
+ require 'kind/maybe/wrappable'
13
+ require 'kind/maybe/typed'
15
14
 
16
- alias_method :new, :wrap
17
- alias_method :[], :wrap
15
+ def new(value)
16
+ (KIND.null?(value) ? None : Some)
17
+ .new(value)
18
18
  end
19
19
 
20
- module Value
21
- def self.none?(value)
22
- value.nil? || Undefined == value
23
- end
20
+ alias_method :[], :new
24
21
 
25
- def self.some?(value)
26
- !none?(value)
27
- end
28
- end
29
-
30
- class Result
31
- attr_reader :value
32
-
33
- def initialize(value)
34
- @value = value.kind_of?(Result) ? value.value : value
35
- end
36
-
37
- def value_or(method_name = Undefined, &block)
38
- raise NotImplementedError
39
- end
40
-
41
- def none?
42
- raise NotImplementedError
43
- end
44
-
45
- def some?; !none?; end
46
-
47
- def map(&fn)
48
- raise NotImplementedError
49
- end
50
-
51
- def try(method_name = Undefined, &block)
52
- raise NotImplementedError
53
- end
54
- end
55
-
56
- class None < Result
57
- INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
58
-
59
- def value_or(default = Undefined, &block)
60
- raise ArgumentError, INVALID_DEFAULT_ARG if Undefined == default && !block
61
-
62
- Undefined != default ? default : block.call
63
- end
64
-
65
- def none?; true; end
66
-
67
- def map(&fn)
68
- self
69
- end
70
-
71
- alias_method :then, :map
72
-
73
- def try!(method_name = Undefined, *args, &block)
74
- Kind.of.Symbol(method_name) if Undefined != method_name
75
-
76
- NONE_WITH_NIL_VALUE
77
- end
78
-
79
- alias_method :try, :try!
80
-
81
- def dig(*keys)
82
- NONE_WITH_NIL_VALUE
83
- end
84
-
85
- private_constant :INVALID_DEFAULT_ARG
86
- end
87
-
88
- NONE_WITH_NIL_VALUE = None.new(nil)
89
- NONE_WITH_UNDEFINED_VALUE = None.new(Undefined)
90
-
91
- private_constant :NONE_WITH_NIL_VALUE, :NONE_WITH_UNDEFINED_VALUE
92
-
93
- class Some < Result
94
- def value_or(default = Undefined, &block)
95
- @value
96
- end
97
-
98
- def none?; false; end
99
-
100
- def map(&fn)
101
- result = fn.call(@value)
102
-
103
- resolve(result)
104
- end
105
-
106
- alias_method :then, :map
107
-
108
- def try!(method_name = Undefined, *args, &block)
109
- Kind::Of::Symbol(method_name) if Undefined != method_name
110
-
111
- __try__(method_name, args, block)
112
- end
113
-
114
- def try(method_name = Undefined, *args, &block)
115
- if (Undefined != method_name && value.respond_to?(Kind::Of::Symbol(method_name))) ||
116
- (Undefined == method_name && block)
117
- __try__(method_name, args, block)
118
- else
119
- NONE_WITH_NIL_VALUE
120
- end
121
- end
122
-
123
- def dig(*keys)
124
- resolve(Kind::Dig.call(value, keys))
125
- end
126
-
127
- private
128
-
129
- def __try__(method_name = Undefined, args, block)
130
- fn = Undefined == method_name ? block : method_name.to_proc
131
-
132
- result = args.empty? ? fn.call(value) : fn.call(*args.unshift(value))
133
-
134
- resolve(result)
135
- end
136
-
137
- def resolve(result)
138
- return result if Maybe::None === result
139
- return NONE_WITH_NIL_VALUE if result.nil?
140
- return NONE_WITH_UNDEFINED_VALUE if Undefined == result
141
-
142
- Some.new(result)
143
- end
144
- end
145
-
146
- def self.new(value)
147
- result_type = Maybe::Value.none?(value) ? None : Some
148
- result_type.new(value)
149
- end
150
-
151
- def self.[](value)
152
- new(value)
153
- end
154
-
155
- def self.wrap(value)
156
- new(value)
157
- end
158
-
159
- def self.none
160
- NONE_WITH_NIL_VALUE
161
- end
162
-
163
- VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
164
-
165
- private_constant :VALUE_CANT_BE_NONE
166
-
167
- def self.some(value)
168
- return Maybe::Some.new(value) if Value.some?(value)
169
-
170
- raise ArgumentError, VALUE_CANT_BE_NONE
171
- end
22
+ extend Wrappable
172
23
  end
173
24
 
174
25
  Optional = Maybe
@@ -176,7 +27,7 @@ module Kind
176
27
  None = Maybe.none
177
28
 
178
29
  def self.None
179
- Kind::None
30
+ None
180
31
  end
181
32
 
182
33
  def self.Some(value)
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class None < Result
6
+ INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
7
+
8
+ def value_or(default = UNDEFINED, &block)
9
+ raise ArgumentError, INVALID_DEFAULT_ARG if UNDEFINED == default && !block
10
+
11
+ UNDEFINED != default ? default : block.call
12
+ end
13
+
14
+ def none?; true; end
15
+
16
+ def map(&fn)
17
+ self
18
+ end
19
+
20
+ alias_method :map!, :map
21
+ alias_method :then, :map
22
+ alias_method :then!, :map
23
+ alias_method :check, :map
24
+
25
+ def try!(method_name = UNDEFINED, *args, &block)
26
+ Kind::Symbol[method_name] if UNDEFINED != method_name
27
+
28
+ self
29
+ end
30
+
31
+ alias_method :try, :try!
32
+
33
+ def dig(*keys)
34
+ self
35
+ end
36
+
37
+ def presence
38
+ self
39
+ end
40
+
41
+ private_constant :INVALID_DEFAULT_ARG
42
+ end
43
+
44
+ NONE_WITH_NIL_VALUE = None.new(nil)
45
+ NONE_WITH_UNDEFINED_VALUE = None.new(Undefined)
46
+
47
+ def none
48
+ NONE_WITH_NIL_VALUE
49
+ end
50
+
51
+ def __none__(value) # :nodoc:
52
+ None.new(value)
53
+ end
54
+
55
+ private_constant :NONE_WITH_NIL_VALUE, :NONE_WITH_UNDEFINED_VALUE
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class Result
6
+ attr_reader :value
7
+
8
+ Value = ->(arg) { arg.kind_of?(::Kind::Maybe::Result) ? arg.value : arg } # :nodoc:
9
+
10
+ def initialize(arg)
11
+ @value = Value.(arg)
12
+ end
13
+
14
+ def value_or(method_name = UNDEFINED, &block)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def none?
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def some?; !none?; end
23
+
24
+ def map(&fn)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ alias_method :map!, :map
29
+ alias_method :then, :map
30
+ alias_method :then!, :map
31
+
32
+ def check(&fn)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def try(method_name = UNDEFINED, &block)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ alias_method :try!, :try
41
+
42
+ def dig(*keys)
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def presence
47
+ raise NotImplementedError
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class Some < Result
6
+ def value_or(default = UNDEFINED, &block)
7
+ @value
8
+ end
9
+
10
+ def none?; false; end
11
+
12
+ def map(&fn)
13
+ map!(&fn)
14
+ rescue StandardError => exception
15
+ None.new(exception)
16
+ end
17
+
18
+ alias_method :then, :map
19
+
20
+ def check(&fn)
21
+ result = fn.call(@value)
22
+
23
+ !result || KIND.null?(result) ? NONE_WITH_NIL_VALUE : self
24
+ end
25
+
26
+ def map!(&fn)
27
+ result = fn.call(@value)
28
+
29
+ resolve(result)
30
+ end
31
+
32
+ alias_method :then!, :map!
33
+
34
+ def try!(method_name = UNDEFINED, *args, &block)
35
+ return __try_block__(block, args) if block
36
+
37
+ return __try_method__(method_name, args) if UNDEFINED != method_name
38
+
39
+ raise ArgumentError, 'method name or a block must be present'
40
+ end
41
+
42
+ def try(method_name = UNDEFINED, *args, &block)
43
+ return __try_block__(block, args) if block
44
+
45
+ return __try_method__(method_name, args) if value.respond_to?(method_name)
46
+
47
+ NONE_WITH_NIL_VALUE
48
+ end
49
+
50
+ def dig(*keys)
51
+ resolve(Dig.(value, keys))
52
+ end
53
+
54
+ def presence
55
+ resolve(Presence.(value))
56
+ end
57
+
58
+ private
59
+
60
+ def __try_method__(method_name, args)
61
+ __try_block__(Kind::Symbol[method_name].to_proc, args)
62
+ end
63
+
64
+ def __try_block__(block, args)
65
+ result = args.empty? ? block.call(value) : block.call(*args.unshift(value))
66
+
67
+ resolve(result)
68
+ end
69
+
70
+ def resolve(result)
71
+ return result if Maybe::None === result
72
+ return None.new(result) if Exception === result
73
+ return NONE_WITH_NIL_VALUE if result.nil?
74
+ return NONE_WITH_UNDEFINED_VALUE if Undefined == result
75
+
76
+ Some.new(result)
77
+ end
78
+ end
79
+
80
+ VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
81
+
82
+ def some(value)
83
+ return Maybe::Some.new(value) if !KIND.null?(value)
84
+
85
+ raise ArgumentError, VALUE_CANT_BE_NONE
86
+ end
87
+
88
+ private_constant :VALUE_CANT_BE_NONE
89
+ end
90
+ end