kind 3.0.0 → 5.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +37 -12
  4. data/.travis.yml +6 -5
  5. data/CHANGELOG.md +1295 -0
  6. data/Gemfile +10 -2
  7. data/README.md +985 -490
  8. data/lib/kind.rb +35 -287
  9. data/lib/kind/active_model/kind_validator.rb +20 -13
  10. data/lib/kind/core.rb +8 -0
  11. data/lib/kind/core/kind.rb +61 -0
  12. data/lib/kind/core/undefined.rb +7 -0
  13. data/lib/kind/dig.rb +40 -0
  14. data/lib/kind/empty.rb +4 -12
  15. data/lib/kind/empty/constant.rb +7 -0
  16. data/lib/kind/error.rb +2 -6
  17. data/lib/kind/maybe.rb +14 -153
  18. data/lib/kind/maybe/none.rb +57 -0
  19. data/lib/kind/maybe/result.rb +51 -0
  20. data/lib/kind/maybe/some.rb +90 -0
  21. data/lib/kind/maybe/typed.rb +29 -0
  22. data/lib/kind/maybe/wrappable.rb +33 -0
  23. data/lib/kind/presence.rb +33 -0
  24. data/lib/kind/try.rb +34 -0
  25. data/lib/kind/type_checker.rb +87 -0
  26. data/lib/kind/type_checkers.rb +30 -0
  27. data/lib/kind/type_checkers/core/array.rb +17 -0
  28. data/lib/kind/type_checkers/core/class.rb +13 -0
  29. data/lib/kind/type_checkers/core/comparable.rb +13 -0
  30. data/lib/kind/type_checkers/core/enumerable.rb +13 -0
  31. data/lib/kind/type_checkers/core/enumerator.rb +13 -0
  32. data/lib/kind/type_checkers/core/file.rb +13 -0
  33. data/lib/kind/type_checkers/core/float.rb +13 -0
  34. data/lib/kind/type_checkers/core/hash.rb +17 -0
  35. data/lib/kind/type_checkers/core/integer.rb +13 -0
  36. data/lib/kind/type_checkers/core/io.rb +13 -0
  37. data/lib/kind/type_checkers/core/method.rb +13 -0
  38. data/lib/kind/type_checkers/core/module.rb +17 -0
  39. data/lib/kind/type_checkers/core/numeric.rb +13 -0
  40. data/lib/kind/type_checkers/core/proc.rb +13 -0
  41. data/lib/kind/type_checkers/core/queue.rb +14 -0
  42. data/lib/kind/type_checkers/core/range.rb +13 -0
  43. data/lib/kind/type_checkers/core/regexp.rb +13 -0
  44. data/lib/kind/type_checkers/core/string.rb +17 -0
  45. data/lib/kind/type_checkers/core/struct.rb +13 -0
  46. data/lib/kind/type_checkers/core/symbol.rb +13 -0
  47. data/lib/kind/type_checkers/core/time.rb +13 -0
  48. data/lib/kind/type_checkers/custom/boolean.rb +19 -0
  49. data/lib/kind/type_checkers/custom/callable.rb +19 -0
  50. data/lib/kind/type_checkers/custom/lambda.rb +19 -0
  51. data/lib/kind/type_checkers/stdlib/open_struct.rb +13 -0
  52. data/lib/kind/type_checkers/stdlib/set.rb +17 -0
  53. data/lib/kind/undefined.rb +4 -2
  54. data/lib/kind/validator.rb +1 -1
  55. data/lib/kind/version.rb +1 -1
  56. data/test.sh +4 -4
  57. metadata +45 -9
  58. data/lib/kind/checker.rb +0 -15
  59. data/lib/kind/checker/factory.rb +0 -35
  60. data/lib/kind/checker/protocol.rb +0 -73
  61. data/lib/kind/is.rb +0 -19
  62. data/lib/kind/of.rb +0 -11
  63. data/lib/kind/types.rb +0 -115
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class Typed
6
+ include Wrappable
7
+
8
+ def initialize(kind)
9
+ @kind = kind
10
+ end
11
+
12
+ def new(arg)
13
+ value = Result::Value.(arg)
14
+
15
+ @kind === value ? Maybe.some(value) : Maybe.none
16
+ end
17
+
18
+ alias_method :[], :new
19
+
20
+ private
21
+
22
+ def __call_before_expose_the_arg_in_a_block(arg)
23
+ value = Result::Value.(arg)
24
+
25
+ @kind === value ? value : Maybe.none
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ module Wrappable
6
+ def wrap(arg = UNDEFINED)
7
+ if block_given?
8
+ begin
9
+ return new(yield) if UNDEFINED == arg
10
+
11
+ input = __call_before_expose_the_arg_in_a_block(arg)
12
+
13
+ input.kind_of?(Maybe::None) ? input : new(yield(input))
14
+ rescue StandardError => exception
15
+ Maybe.__none__(exception)
16
+ end
17
+ else
18
+ return new(arg) if UNDEFINED != arg
19
+
20
+ raise ArgumentError, 'wrong number of arguments (given 0, expected 1)'
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def __call_before_expose_the_arg_in_a_block(input)
27
+ input
28
+ end
29
+ end
30
+
31
+ private_constant :Wrappable
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Presence
5
+ extend self
6
+
7
+ def call(object)
8
+ return object.blank? ? nil : object if object.respond_to?(:blank?)
9
+
10
+ return object if TrueClass === object
11
+
12
+ return blank_str?(object) ? nil : object if String === object
13
+
14
+ return object.empty? ? nil : object if object.respond_to?(:empty?)
15
+
16
+ return object if object
17
+ end
18
+
19
+ def to_proc
20
+ -> object { call(object) }
21
+ end
22
+
23
+ private
24
+
25
+ BLANK_RE = /\A[[:space:]]*\z/
26
+
27
+ def blank_str?(object)
28
+ object.empty? || BLANK_RE === object
29
+ end
30
+
31
+ private_constant :BLANK_RE
32
+ end
33
+ end
data/lib/kind/try.rb ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Try
5
+ extend self
6
+
7
+ def call(*args)
8
+ object = args.shift
9
+
10
+ call!(object, args.shift, args)
11
+ end
12
+
13
+ def self.[](*args)
14
+ method_name = args.shift
15
+
16
+ ->(object) { call!(object, method_name, args) }
17
+ end
18
+
19
+ def call!(object, method_name, args) # :nodoc
20
+ return if KIND.null?(object)
21
+
22
+ resolve(object, method_name, args)
23
+ end
24
+
25
+ private
26
+
27
+ def resolve(object, method_name, args = Empty::ARRAY)
28
+ return unless object.respond_to?(method_name)
29
+ return object.public_send(method_name) if args.empty?
30
+
31
+ object.public_send(method_name, *args)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module TypeChecker
5
+ def name
6
+ kind.name
7
+ end
8
+
9
+ def ===(value)
10
+ kind === value
11
+ end
12
+
13
+ def [](value)
14
+ return value if self === value
15
+
16
+ KIND.error!(name, value)
17
+ end
18
+
19
+ def or_nil(value)
20
+ return value if self === value
21
+ end
22
+
23
+ def or_undefined(value)
24
+ or_nil(value) || Undefined
25
+ end
26
+
27
+ def or(fallback, value = UNDEFINED)
28
+ return __or_func.(fallback) if UNDEFINED === value
29
+
30
+ self === value ? value : fallback
31
+ end
32
+
33
+ def value?(value = UNDEFINED)
34
+ return self === value if UNDEFINED != value
35
+
36
+ @__is_value ||= ->(ck) { ->(value) { ck === value } }.(self)
37
+ end
38
+
39
+ def value(arg, default:)
40
+ KIND.value(self, arg, self[default])
41
+ end
42
+
43
+ def or_null(value) # :nodoc:
44
+ KIND.null?(value) ? value : self[value]
45
+ end
46
+
47
+ def maybe(value = UNDEFINED, &block)
48
+ return __maybe[value] if UNDEFINED != value && !block
49
+ return __maybe.wrap(&block) if UNDEFINED == value && block
50
+ return __maybe.wrap(value, &block) if UNDEFINED != value && block
51
+
52
+ __maybe
53
+ end
54
+
55
+ alias optional maybe
56
+
57
+ private
58
+
59
+ def __maybe
60
+ @__maybe ||= Maybe::Typed.new(self)
61
+ end
62
+
63
+ def __or_func
64
+ @__or_func ||= ->(tc, fb, value) { tc === value ? value : tc.or_null(fb) }.curry[self]
65
+ end
66
+ end
67
+
68
+ class TypeChecker::Object # :nodoc: all
69
+ include TypeChecker
70
+
71
+ ResolveKindName = ->(kind, opt) do
72
+ name = Try.(opt, :[], :name)
73
+ name || Try.(kind, :name)
74
+ end
75
+
76
+ attr_reader :kind, :name
77
+
78
+ def initialize(kind, opt)
79
+ name = ResolveKindName.(kind, opt)
80
+
81
+ @name = KIND.of!(::String, name)
82
+ @kind = KIND.respond_to!(:===, kind)
83
+ end
84
+
85
+ private_constant :ResolveKindName
86
+ end
87
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/type_checkers/core/array'
4
+ require 'kind/type_checkers/core/class'
5
+ require 'kind/type_checkers/core/comparable'
6
+ require 'kind/type_checkers/core/enumerable'
7
+ require 'kind/type_checkers/core/enumerator'
8
+ require 'kind/type_checkers/core/file'
9
+ require 'kind/type_checkers/core/float'
10
+ require 'kind/type_checkers/core/hash'
11
+ require 'kind/type_checkers/core/integer'
12
+ require 'kind/type_checkers/core/io'
13
+ require 'kind/type_checkers/core/module'
14
+ require 'kind/type_checkers/core/method'
15
+ require 'kind/type_checkers/core/numeric'
16
+ require 'kind/type_checkers/core/proc'
17
+ require 'kind/type_checkers/core/queue'
18
+ require 'kind/type_checkers/core/range'
19
+ require 'kind/type_checkers/core/regexp'
20
+ require 'kind/type_checkers/core/string'
21
+ require 'kind/type_checkers/core/struct'
22
+ require 'kind/type_checkers/core/symbol'
23
+ require 'kind/type_checkers/core/time'
24
+
25
+ require 'kind/type_checkers/stdlib/open_struct'
26
+ require 'kind/type_checkers/stdlib/set'
27
+
28
+ require 'kind/type_checkers/custom/boolean'
29
+ require 'kind/type_checkers/custom/callable'
30
+ require 'kind/type_checkers/custom/lambda'
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Array
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Array; end
8
+
9
+ def value_or_empty(arg)
10
+ KIND.value(self, arg, Empty::ARRAY)
11
+ end
12
+ end
13
+
14
+ def self.Array?(*values)
15
+ KIND.of?(::Array, values)
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Class
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Class; end
8
+ end
9
+
10
+ def self.Class?(*values)
11
+ KIND.of?(::Class, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Comparable
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Comparable; end
8
+ end
9
+
10
+ def self.Comparable?(*values)
11
+ KIND.of?(::Comparable, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Enumerable
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Enumerable; end
8
+ end
9
+
10
+ def self.Enumerable?(*values)
11
+ KIND.of?(::Enumerable, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Enumerator
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Enumerator; end
8
+ end
9
+
10
+ def self.Enumerator?(*values)
11
+ KIND.of?(::Enumerator, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module File
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::File; end
8
+ end
9
+
10
+ def self.File?(*values)
11
+ KIND.of?(::File, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Float
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Float; end
8
+ end
9
+
10
+ def self.Float?(*values)
11
+ KIND.of?(::Float, values)
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Hash
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Hash; end
8
+
9
+ def value_or_empty(arg)
10
+ KIND.value(self, arg, Empty::HASH)
11
+ end
12
+ end
13
+
14
+ def self.Hash?(*values)
15
+ KIND.of?(::Hash, values)
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Integer
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Integer; end
8
+ end
9
+
10
+ def self.Integer?(*values)
11
+ KIND.of?(::Integer, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module IO
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::IO; end
8
+ end
9
+
10
+ def self.IO?(*values)
11
+ KIND.of?(::IO, values)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Method
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Method; end
8
+ end
9
+
10
+ def self.Method?(*values)
11
+ KIND.of?(::Method, values)
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Module
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Module; end
8
+
9
+ def ===(value)
10
+ Kind.of_module?(value)
11
+ end
12
+ end
13
+
14
+ def self.Module?(*values)
15
+ KIND.of?(::Kind::Module, values)
16
+ end
17
+ end