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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +39 -7
  4. data/.travis.yml +1 -2
  5. data/CHANGELOG.md +486 -28
  6. data/Gemfile +13 -6
  7. data/README.md +153 -49
  8. data/kind.gemspec +1 -1
  9. data/lib/kind.rb +2 -84
  10. data/lib/kind/__lib__/action_steps.rb +57 -0
  11. data/lib/kind/__lib__/attributes.rb +66 -0
  12. data/lib/kind/__lib__/kind.rb +51 -0
  13. data/lib/kind/__lib__/of.rb +17 -0
  14. data/lib/kind/__lib__/strict.rb +49 -0
  15. data/lib/kind/__lib__/undefined.rb +14 -0
  16. data/lib/kind/action.rb +127 -0
  17. data/lib/kind/active_model/validation.rb +3 -4
  18. data/lib/kind/basic.rb +79 -0
  19. data/lib/kind/basic/error.rb +29 -0
  20. data/lib/kind/{undefined.rb → basic/undefined.rb} +6 -1
  21. data/lib/kind/dig.rb +21 -5
  22. data/lib/kind/either.rb +30 -0
  23. data/lib/kind/either/left.rb +29 -0
  24. data/lib/kind/either/methods.rb +17 -0
  25. data/lib/kind/either/monad.rb +65 -0
  26. data/lib/kind/either/monad/wrapper.rb +19 -0
  27. data/lib/kind/either/right.rb +38 -0
  28. data/lib/kind/empty.rb +2 -2
  29. data/lib/kind/empty/constant.rb +7 -0
  30. data/lib/kind/enum.rb +63 -0
  31. data/lib/kind/enum/item.rb +40 -0
  32. data/lib/kind/enum/methods.rb +72 -0
  33. data/lib/kind/function.rb +45 -0
  34. data/lib/kind/functional.rb +89 -0
  35. data/lib/kind/functional/action.rb +90 -0
  36. data/lib/kind/immutable_attributes.rb +34 -0
  37. data/lib/kind/immutable_attributes/initializer.rb +70 -0
  38. data/lib/kind/immutable_attributes/reader.rb +38 -0
  39. data/lib/kind/maybe.rb +37 -12
  40. data/lib/kind/maybe/methods.rb +21 -0
  41. data/lib/kind/maybe/monad.rb +82 -0
  42. data/lib/kind/maybe/monad/wrapper.rb +19 -0
  43. data/lib/kind/maybe/none.rb +12 -19
  44. data/lib/kind/maybe/some.rb +68 -26
  45. data/lib/kind/maybe/typed.rb +11 -5
  46. data/lib/kind/maybe/{wrappable.rb → wrapper.rb} +9 -7
  47. data/lib/kind/monad.rb +22 -0
  48. data/lib/kind/monads.rb +5 -0
  49. data/lib/kind/objects.rb +17 -0
  50. data/lib/kind/objects/basic_object.rb +43 -0
  51. data/lib/kind/objects/modules.rb +32 -0
  52. data/lib/kind/{type_checkers → objects/modules}/core/array.rb +3 -1
  53. data/lib/kind/{type_checkers → objects/modules}/core/class.rb +1 -1
  54. data/lib/kind/{type_checkers → objects/modules}/core/comparable.rb +1 -1
  55. data/lib/kind/{type_checkers → objects/modules}/core/enumerable.rb +1 -1
  56. data/lib/kind/{type_checkers → objects/modules}/core/enumerator.rb +1 -1
  57. data/lib/kind/{type_checkers → objects/modules}/core/file.rb +1 -1
  58. data/lib/kind/{type_checkers → objects/modules}/core/float.rb +1 -1
  59. data/lib/kind/{type_checkers → objects/modules}/core/hash.rb +3 -1
  60. data/lib/kind/{type_checkers → objects/modules}/core/integer.rb +1 -1
  61. data/lib/kind/{type_checkers → objects/modules}/core/io.rb +1 -1
  62. data/lib/kind/{type_checkers → objects/modules}/core/method.rb +1 -1
  63. data/lib/kind/{type_checkers → objects/modules}/core/module.rb +1 -1
  64. data/lib/kind/{type_checkers → objects/modules}/core/numeric.rb +1 -1
  65. data/lib/kind/{type_checkers → objects/modules}/core/proc.rb +1 -1
  66. data/lib/kind/{type_checkers → objects/modules}/core/queue.rb +1 -1
  67. data/lib/kind/{type_checkers → objects/modules}/core/range.rb +1 -1
  68. data/lib/kind/{type_checkers → objects/modules}/core/regexp.rb +1 -1
  69. data/lib/kind/{type_checkers → objects/modules}/core/string.rb +3 -1
  70. data/lib/kind/{type_checkers → objects/modules}/core/struct.rb +1 -1
  71. data/lib/kind/{type_checkers → objects/modules}/core/symbol.rb +1 -1
  72. data/lib/kind/{type_checkers → objects/modules}/core/time.rb +1 -1
  73. data/lib/kind/{type_checkers → objects/modules}/custom/boolean.rb +2 -2
  74. data/lib/kind/{type_checkers → objects/modules}/custom/callable.rb +1 -1
  75. data/lib/kind/{type_checkers → objects/modules}/custom/lambda.rb +1 -1
  76. data/lib/kind/{type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
  77. data/lib/kind/{type_checkers → objects/modules}/stdlib/set.rb +3 -1
  78. data/lib/kind/objects/nil.rb +17 -0
  79. data/lib/kind/objects/not_nil.rb +9 -0
  80. data/lib/kind/objects/object.rb +56 -0
  81. data/lib/kind/objects/respond_to.rb +30 -0
  82. data/lib/kind/objects/union_type.rb +44 -0
  83. data/lib/kind/presence.rb +4 -2
  84. data/lib/kind/result.rb +31 -0
  85. data/lib/kind/result/abstract.rb +53 -0
  86. data/lib/kind/result/failure.rb +33 -0
  87. data/lib/kind/result/methods.rb +17 -0
  88. data/lib/kind/result/monad.rb +74 -0
  89. data/lib/kind/result/monad/wrapper.rb +19 -0
  90. data/lib/kind/result/success.rb +53 -0
  91. data/lib/kind/strict/disabled.rb +34 -0
  92. data/lib/kind/try.rb +21 -11
  93. data/lib/kind/validator.rb +111 -0
  94. data/lib/kind/version.rb +1 -1
  95. metadata +78 -48
  96. data/lib/kind/active_model/kind_validator.rb +0 -96
  97. data/lib/kind/core.rb +0 -9
  98. data/lib/kind/core/deprecation.rb +0 -29
  99. data/lib/kind/core/kind.rb +0 -61
  100. data/lib/kind/core/undefined.rb +0 -7
  101. data/lib/kind/deprecations/built_in_type_checkers.rb +0 -23
  102. data/lib/kind/deprecations/checker.rb +0 -16
  103. data/lib/kind/deprecations/checker/factory.rb +0 -31
  104. data/lib/kind/deprecations/checker/protocol.rb +0 -73
  105. data/lib/kind/deprecations/is.rb +0 -35
  106. data/lib/kind/deprecations/of.rb +0 -258
  107. data/lib/kind/deprecations/types.rb +0 -121
  108. data/lib/kind/error.rb +0 -15
  109. data/lib/kind/maybe/result.rb +0 -51
  110. data/lib/kind/type_checker.rb +0 -73
  111. data/lib/kind/type_checkers.rb +0 -30
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Kind
4
4
  module Boolean
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
- def kind; [TrueClass, FalseClass].freeze; end
7
+ def kind; [TrueClass, FalseClass]; end
8
8
 
9
9
  def name; 'Boolean'; end
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Callable
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; raise NotImplementedError; end
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Lambda
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Proc; end
8
8
 
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ostruct'
4
+
3
5
  module Kind
4
6
  module OpenStruct
5
- extend self, TypeChecker
7
+ extend self, ::Kind::Object
6
8
 
7
9
  def kind; ::OpenStruct; end
8
10
  end
@@ -2,13 +2,15 @@
2
2
 
3
3
  module Kind
4
4
  module Set
5
- extend self, TypeChecker
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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Nil
5
+ def self.|(another_kind)
6
+ UnionType[self] | another_kind
7
+ end
8
+
9
+ def self.name
10
+ 'nil'
11
+ end
12
+
13
+ def self.===(value)
14
+ value.nil?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module NotNil
5
+ def self.[](value, label: nil)
6
+ STRICT.not_nil(value, label)
7
+ end
8
+ end
9
+ end
@@ -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 object.blank? ? nil : object if object.respond_to?(:blank?)
10
+ return if KIND.nil_or_undefined?(object)
9
11
 
10
- return object if TrueClass === 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
 
@@ -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