kind 2.2.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +37 -12
  4. data/.travis.yml +10 -4
  5. data/CHANGELOG.md +1230 -0
  6. data/Gemfile +10 -2
  7. data/README.md +938 -460
  8. data/lib/kind.rb +52 -298
  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/deprecations/checker.rb +16 -0
  16. data/lib/kind/deprecations/checker/factory.rb +31 -0
  17. data/lib/kind/deprecations/checker/protocol.rb +73 -0
  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} +15 -9
  21. data/lib/kind/dig.rb +40 -0
  22. data/lib/kind/empty.rb +5 -11
  23. data/lib/kind/error.rb +2 -6
  24. data/lib/kind/maybe.rb +22 -113
  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 +52 -7
  65. data/lib/kind/checker.rb +0 -83
  66. data/lib/kind/is.rb +0 -19
  67. data/lib/kind/of.rb +0 -11
@@ -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
+ value.kind_of?(@kind) ? 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
+ value.kind_of?(@kind) ? value : Maybe.none
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ module Wrappable
6
+ WRONG_NUMBER_OF_ARGS = 'wrong number of arguments (given 0, expected 1)'.freeze
7
+
8
+ def wrap(arg = UNDEFINED)
9
+ if block_given?
10
+ begin
11
+ return new(yield) if UNDEFINED == arg
12
+
13
+ input = __call_before_expose_the_arg_in_a_block(arg)
14
+
15
+ input.kind_of?(Kind::Maybe::None) ? input : new(yield(input))
16
+ rescue StandardError => exception
17
+ Maybe.__none__(exception)
18
+ end
19
+ else
20
+ return new(arg) if UNDEFINED != arg
21
+
22
+ raise ArgumentError, WRONG_NUMBER_OF_ARGS
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def __call_before_expose_the_arg_in_a_block(input)
29
+ input
30
+ end
31
+ end
32
+
33
+ private_constant :Wrappable
34
+ end
35
+ 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,36 @@
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
+ Array[args]
15
+
16
+ method_name = args.shift
17
+
18
+ ->(object) { call!(object, method_name, args) }
19
+ end
20
+
21
+ def call!(object, method_name, args) # :nodoc
22
+ return if KIND.null?(object)
23
+
24
+ resolve(object, method_name, args)
25
+ end
26
+
27
+ private
28
+
29
+ def resolve(object, method_name, args = Empty::ARRAY)
30
+ return unless object.respond_to?(method_name)
31
+ return object.public_send(method_name) if args.empty?
32
+
33
+ object.public_send(method_name, *args)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,73 @@
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
+ private
48
+
49
+ def __or_func
50
+ @__or_func ||= ->(tc, fb, value) { tc === value ? value : tc.or_null(fb) }.curry[self]
51
+ end
52
+ end
53
+
54
+ class TypeChecker::Object # :nodoc: all
55
+ include TypeChecker
56
+
57
+ ResolveKindName = ->(kind, opt) do
58
+ name = Try.(opt, :[], :name)
59
+ name || Try.(kind, :name)
60
+ end
61
+
62
+ attr_reader :kind, :name
63
+
64
+ def initialize(kind, opt)
65
+ name = ResolveKindName.(kind, opt)
66
+
67
+ @name = KIND.of!(::String, name)
68
+ @kind = KIND.respond_to!(:===, kind)
69
+ end
70
+
71
+ private_constant :ResolveKindName
72
+ end
73
+ 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
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Numeric
5
+ extend self, TypeChecker
6
+
7
+ def kind; ::Numeric; end
8
+ end
9
+
10
+ def self.Numeric?(*values)
11
+ KIND.of?(::Numeric, values)
12
+ end
13
+ end