kind 5.0.0 → 5.4.1

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +39 -7
  4. data/.travis.yml +1 -0
  5. data/CHANGELOG.md +506 -28
  6. data/Gemfile +13 -6
  7. data/README.md +50 -42
  8. data/kind.gemspec +3 -3
  9. data/lib/kind.rb +2 -60
  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 -0
  29. data/lib/kind/enum.rb +63 -0
  30. data/lib/kind/enum/item.rb +40 -0
  31. data/lib/kind/enum/methods.rb +72 -0
  32. data/lib/kind/function.rb +45 -0
  33. data/lib/kind/functional.rb +89 -0
  34. data/lib/kind/functional/action.rb +87 -0
  35. data/lib/kind/functional/steps.rb +22 -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} +8 -4
  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 +22 -10
  93. data/lib/kind/validator.rb +111 -0
  94. data/lib/kind/version.rb +1 -1
  95. metadata +83 -42
  96. data/lib/kind/active_model/kind_validator.rb +0 -103
  97. data/lib/kind/core.rb +0 -8
  98. data/lib/kind/core/kind.rb +0 -61
  99. data/lib/kind/core/undefined.rb +0 -7
  100. data/lib/kind/error.rb +0 -15
  101. data/lib/kind/maybe/result.rb +0 -51
  102. data/lib/kind/type_checker.rb +0 -87
  103. data/lib/kind/type_checkers.rb +0 -30
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ require 'kind/monad'
5
+
6
+ class Maybe::Monad::Wrapper < Kind::Monad::Wrapper
7
+ def none(matcher = UNDEFINED)
8
+ return if @monad.some? || output?
9
+
10
+ @output = yield(@monad.value) if @monad.maybe?(matcher)
11
+ end
12
+
13
+ def some(matcher = UNDEFINED)
14
+ return if @monad.none? || output?
15
+
16
+ @output = yield(@monad.value) if @monad.maybe?(matcher)
17
+ end
18
+ end
19
+ end
@@ -2,18 +2,16 @@
2
2
 
3
3
  module Kind
4
4
  module Maybe
5
- class None < Result
6
- INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
7
-
5
+ class None < Monad
8
6
  def value_or(default = UNDEFINED, &block)
9
- raise ArgumentError, INVALID_DEFAULT_ARG if UNDEFINED == default && !block
7
+ Error.invalid_default_arg! if UNDEFINED == default && !block
10
8
 
11
9
  UNDEFINED != default ? default : block.call
12
10
  end
13
11
 
14
12
  def none?; true; end
15
13
 
16
- def map(&fn)
14
+ def map(_method_name = UNDEFINED, &fn)
17
15
  self
18
16
  end
19
17
 
@@ -21,9 +19,13 @@ module Kind
21
19
  alias_method :then, :map
22
20
  alias_method :then!, :map
23
21
  alias_method :check, :map
22
+ alias_method :accept, :map
23
+ alias_method :reject, :map
24
+ alias_method :and_then, :map
25
+ alias_method :and_then!, :map!
24
26
 
25
27
  def try!(method_name = UNDEFINED, *args, &block)
26
- KIND.of!(::Symbol, method_name)if UNDEFINED != method_name
28
+ STRICT.kind_of(::Symbol, method_name)if UNDEFINED != method_name
27
29
 
28
30
  self
29
31
  end
@@ -38,20 +40,11 @@ module Kind
38
40
  self
39
41
  end
40
42
 
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)
43
+ def inspect
44
+ '#<%s value=%s>' % ['Kind::None', value.inspect]
45
+ end
53
46
  end
54
47
 
55
- private_constant :NONE_WITH_NIL_VALUE, :NONE_WITH_UNDEFINED_VALUE
48
+ NONE_INSTANCE = None.new(nil)
56
49
  end
57
50
  end
@@ -1,35 +1,80 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kind/dig'
4
+ require 'kind/presence'
5
+
3
6
  module Kind
4
7
  module Maybe
5
- class Some < Result
6
- def value_or(default = UNDEFINED, &block)
8
+ class Some < Monad
9
+ KindSymbol = ->(value) { STRICT.kind_of(::Symbol, value) }
10
+
11
+ VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
12
+
13
+ def self.[](value)
14
+ return new(value) if !KIND.nil_or_undefined?(value)
15
+
16
+ raise ArgumentError, VALUE_CANT_BE_NONE
17
+ end
18
+
19
+ def value_or(_default = UNDEFINED, &block)
7
20
  @value
8
21
  end
9
22
 
10
23
  def none?; false; end
11
24
 
12
- def map(&fn)
13
- map!(&fn)
25
+ def map(method_name = UNDEFINED, &fn)
26
+ map!(method_name, &fn)
14
27
  rescue StandardError => exception
15
28
  None.new(exception)
16
29
  end
17
30
 
18
31
  alias_method :then, :map
32
+ alias_method :and_then, :map
19
33
 
20
- def check(&fn)
21
- result = fn.call(@value)
34
+ def map!(method_name = UNDEFINED, &fn)
35
+ result = if UNDEFINED != method_name
36
+ return NONE_INSTANCE unless @value.respond_to?(KindSymbol[method_name])
22
37
 
23
- !result || KIND.null?(result) ? NONE_WITH_NIL_VALUE : self
24
- end
25
-
26
- def map!(&fn)
27
- result = fn.call(@value)
38
+ @value.public_send(method_name)
39
+ else
40
+ fn.call(@value)
41
+ end
28
42
 
29
43
  resolve(result)
30
44
  end
31
45
 
32
46
  alias_method :then!, :map!
47
+ alias_method :and_then!, :map!
48
+
49
+ def check(method_name = UNDEFINED, &fn)
50
+ result = if UNDEFINED != method_name
51
+ if method_name.kind_of?(::Symbol)
52
+ @value.respond_to?(method_name) ? @value.public_send(method_name) : NONE_INSTANCE
53
+ else
54
+ method_name === @value
55
+ end
56
+ else
57
+ fn.call(@value)
58
+ end
59
+
60
+ !result || KIND.nil_or_undefined?(result) ? NONE_INSTANCE : self
61
+ end
62
+
63
+ alias_method :accept, :check
64
+
65
+ def reject(method_name = UNDEFINED, &fn)
66
+ result = if UNDEFINED != method_name
67
+ if method_name.kind_of?(::Symbol)
68
+ @value.respond_to?(method_name) ? @value.public_send(method_name) : NONE_INSTANCE
69
+ else
70
+ method_name === @value
71
+ end
72
+ else
73
+ fn.call(@value)
74
+ end
75
+
76
+ result || KIND.nil_or_undefined?(result) ? NONE_INSTANCE : self
77
+ end
33
78
 
34
79
  def try!(method_name = UNDEFINED, *args, &block)
35
80
  return __try_block__(block, args) if block
@@ -44,21 +89,27 @@ module Kind
44
89
 
45
90
  return __try_method__(method_name, args) if value.respond_to?(method_name)
46
91
 
47
- NONE_WITH_NIL_VALUE
92
+ NONE_INSTANCE
93
+ rescue TypeError
94
+ NONE_INSTANCE
48
95
  end
49
96
 
50
97
  def dig(*keys)
51
- resolve(Dig.(value, keys))
98
+ resolve(Dig.call!(value, keys))
52
99
  end
53
100
 
54
101
  def presence
55
102
  resolve(Presence.(value))
56
103
  end
57
104
 
105
+ def inspect
106
+ '#<%s value=%s>' % ['Kind::Some', value.inspect]
107
+ end
108
+
58
109
  private
59
110
 
60
111
  def __try_method__(method_name, args)
61
- __try_block__(KIND.of!(::Symbol, method_name).to_proc, args)
112
+ __try_block__(KindSymbol[method_name].to_proc, args)
62
113
  end
63
114
 
64
115
  def __try_block__(block, args)
@@ -69,22 +120,13 @@ module Kind
69
120
 
70
121
  def resolve(result)
71
122
  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
123
+ return NONE_INSTANCE if KIND.nil_or_undefined?(result)
124
+ return None.new(result) if ::Exception === result
75
125
 
76
126
  Some.new(result)
77
127
  end
78
- end
79
-
80
- VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
81
128
 
82
- def some(value)
83
- return Maybe::Some.new(value) if !KIND.null?(value)
84
-
85
- raise ArgumentError, VALUE_CANT_BE_NONE
129
+ private_constant :KindSymbol, :VALUE_CANT_BE_NONE
86
130
  end
87
-
88
- private_constant :VALUE_CANT_BE_NONE
89
131
  end
90
132
  end
@@ -3,26 +3,32 @@
3
3
  module Kind
4
4
  module Maybe
5
5
  class Typed
6
- include Wrappable
6
+ include Wrapper
7
+
8
+ singleton_class.send(:alias_method, :[], :new)
7
9
 
8
10
  def initialize(kind)
9
11
  @kind = kind
10
12
  end
11
13
 
12
14
  def new(arg)
13
- value = Result::Value.(arg)
15
+ value = Monad::Value[arg]
14
16
 
15
- @kind === value ? Maybe.some(value) : Maybe.none
17
+ @kind === value ? Maybe::Some[value] : Maybe::NONE_INSTANCE
16
18
  end
17
19
 
18
20
  alias_method :[], :new
19
21
 
22
+ def inspect
23
+ "Kind::Maybe<#{@kind}>"
24
+ end
25
+
20
26
  private
21
27
 
22
28
  def __call_before_expose_the_arg_in_a_block(arg)
23
- value = Result::Value.(arg)
29
+ value = Monad::Value[arg]
24
30
 
25
- @kind === value ? value : Maybe.none
31
+ @kind === value ? value : Maybe::NONE_INSTANCE
26
32
  end
27
33
  end
28
34
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Maybe
5
- module Wrappable
5
+ module Wrapper
6
6
  def wrap(arg = UNDEFINED)
7
7
  if block_given?
8
8
  begin
@@ -12,15 +12,19 @@ module Kind
12
12
 
13
13
  input.kind_of?(Maybe::None) ? input : new(yield(input))
14
14
  rescue StandardError => exception
15
- Maybe.__none__(exception)
15
+ Maybe::None.new(exception)
16
16
  end
17
17
  else
18
18
  return new(arg) if UNDEFINED != arg
19
19
 
20
- raise ArgumentError, 'wrong number of arguments (given 0, expected 1)'
20
+ Error.wrong_number_of_args!(given: 0, expected: 1)
21
21
  end
22
22
  end
23
23
 
24
+ def from(&block)
25
+ wrap(&block)
26
+ end
27
+
24
28
  private
25
29
 
26
30
  def __call_before_expose_the_arg_in_a_block(input)
@@ -28,6 +32,6 @@ module Kind
28
32
  end
29
33
  end
30
34
 
31
- private_constant :Wrappable
35
+ private_constant :Wrapper
32
36
  end
33
37
  end
data/lib/kind/monad.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Monad
5
+ Error = ::Class.new(Kind::Error)
6
+
7
+ class Wrapper
8
+ def initialize(monad)
9
+ @monad = monad
10
+ @output = UNDEFINED
11
+ end
12
+
13
+ def output?
14
+ UNDEFINED != @output
15
+ end
16
+
17
+ def output
18
+ @output if output?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/maybe'
4
+ require 'kind/either'
5
+ require 'kind/result'
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/try'
4
+ require 'kind/maybe'
5
+
6
+ require 'kind/objects/basic_object'
7
+ require 'kind/objects/respond_to'
8
+ require 'kind/objects/union_type'
9
+ require 'kind/objects/nil'
10
+ require 'kind/objects/not_nil'
11
+ require 'kind/objects/object'
12
+ require 'kind/objects/modules'
13
+
14
+ module Kind
15
+ UnionType.send(:include, Maybe::Buildable)
16
+ RespondTo.send(:include, Maybe::Buildable)
17
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module BasicObject
5
+ def [](value, label: nil)
6
+ STRICT.object_is_a(self, value, label)
7
+ end
8
+
9
+ def or_nil(value)
10
+ return value if self === value
11
+ end
12
+
13
+ def or_undefined(value)
14
+ or_nil(value) || Undefined
15
+ end
16
+
17
+ def or(fallback, value = UNDEFINED)
18
+ return __or_func.(fallback) if UNDEFINED === value
19
+
20
+ self === value ? value : fallback
21
+ end
22
+
23
+ def value?(value = UNDEFINED)
24
+ return self === value if UNDEFINED != value
25
+
26
+ @__is_value ||= ->(tc) { ->(arg) { tc === arg } }.(self)
27
+ end
28
+
29
+ def value(arg, default:)
30
+ KIND.value(self, arg, self[default])
31
+ end
32
+
33
+ def or_null(value) # :nodoc:
34
+ KIND.nil_or_undefined?(value) ? value : self[value]
35
+ end
36
+
37
+ private
38
+
39
+ def __or_func
40
+ @__or_func ||= ->(tc, fb, value) { tc === value ? value : tc.or_null(fb) }.curry[self]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/empty'
4
+
5
+ require 'kind/objects/modules/core/array'
6
+ require 'kind/objects/modules/core/class'
7
+ require 'kind/objects/modules/core/comparable'
8
+ require 'kind/objects/modules/core/enumerable'
9
+ require 'kind/objects/modules/core/enumerator'
10
+ require 'kind/objects/modules/core/file'
11
+ require 'kind/objects/modules/core/float'
12
+ require 'kind/objects/modules/core/hash'
13
+ require 'kind/objects/modules/core/integer'
14
+ require 'kind/objects/modules/core/io'
15
+ require 'kind/objects/modules/core/module'
16
+ require 'kind/objects/modules/core/method'
17
+ require 'kind/objects/modules/core/numeric'
18
+ require 'kind/objects/modules/core/proc'
19
+ require 'kind/objects/modules/core/queue'
20
+ require 'kind/objects/modules/core/range'
21
+ require 'kind/objects/modules/core/regexp'
22
+ require 'kind/objects/modules/core/string'
23
+ require 'kind/objects/modules/core/struct'
24
+ require 'kind/objects/modules/core/symbol'
25
+ require 'kind/objects/modules/core/time'
26
+
27
+ require 'kind/objects/modules/stdlib/open_struct'
28
+ require 'kind/objects/modules/stdlib/set'
29
+
30
+ require 'kind/objects/modules/custom/boolean'
31
+ require 'kind/objects/modules/custom/callable'
32
+ require 'kind/objects/modules/custom/lambda'
@@ -2,13 +2,15 @@
2
2
 
3
3
  module Kind
4
4
  module Array
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Array; end
8
8
 
9
9
  def value_or_empty(arg)
10
10
  KIND.value(self, arg, Empty::ARRAY)
11
11
  end
12
+
13
+ alias empty_or value_or_empty
12
14
  end
13
15
 
14
16
  def self.Array?(*values)