kind 5.1.0 → 5.5.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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +37 -10
  4. data/CHANGELOG.md +518 -29
  5. data/README.md +48 -45
  6. data/kind.gemspec +2 -2
  7. data/lib/kind.rb +2 -49
  8. data/lib/kind/__lib__/action_steps.rb +57 -0
  9. data/lib/kind/__lib__/attributes.rb +66 -0
  10. data/lib/kind/__lib__/kind.rb +51 -0
  11. data/lib/kind/__lib__/of.rb +17 -0
  12. data/lib/kind/__lib__/strict.rb +49 -0
  13. data/lib/kind/__lib__/undefined.rb +14 -0
  14. data/lib/kind/action.rb +127 -0
  15. data/lib/kind/active_model/validation.rb +1 -1
  16. data/lib/kind/basic.rb +83 -0
  17. data/lib/kind/basic/error.rb +29 -0
  18. data/lib/kind/{core → basic}/undefined.rb +6 -1
  19. data/lib/kind/{core/dig.rb → dig.rb} +21 -5
  20. data/lib/kind/either.rb +30 -0
  21. data/lib/kind/either/left.rb +29 -0
  22. data/lib/kind/either/methods.rb +17 -0
  23. data/lib/kind/either/monad.rb +65 -0
  24. data/lib/kind/either/monad/wrapper.rb +19 -0
  25. data/lib/kind/either/right.rb +38 -0
  26. data/lib/kind/{core/empty.rb → empty.rb} +2 -0
  27. data/lib/kind/{core/empty → empty}/constant.rb +0 -0
  28. data/lib/kind/enum.rb +63 -0
  29. data/lib/kind/enum/item.rb +40 -0
  30. data/lib/kind/enum/methods.rb +72 -0
  31. data/lib/kind/function.rb +45 -0
  32. data/lib/kind/functional.rb +89 -0
  33. data/lib/kind/functional/action.rb +87 -0
  34. data/lib/kind/functional/steps.rb +22 -0
  35. data/lib/kind/immutable_attributes.rb +34 -0
  36. data/lib/kind/immutable_attributes/initializer.rb +70 -0
  37. data/lib/kind/immutable_attributes/reader.rb +38 -0
  38. data/lib/kind/maybe.rb +69 -0
  39. data/lib/kind/maybe/methods.rb +21 -0
  40. data/lib/kind/maybe/monad.rb +82 -0
  41. data/lib/kind/maybe/monad/wrapper.rb +19 -0
  42. data/lib/kind/maybe/none.rb +50 -0
  43. data/lib/kind/maybe/some.rb +132 -0
  44. data/lib/kind/maybe/typed.rb +35 -0
  45. data/lib/kind/{core/maybe/wrappable.rb → maybe/wrapper.rb} +8 -4
  46. data/lib/kind/monad.rb +22 -0
  47. data/lib/kind/monads.rb +5 -0
  48. data/lib/kind/objects.rb +17 -0
  49. data/lib/kind/objects/basic_object.rb +43 -0
  50. data/lib/kind/objects/modules.rb +32 -0
  51. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/array.rb +3 -1
  52. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/class.rb +1 -1
  53. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/comparable.rb +1 -1
  54. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/enumerable.rb +1 -1
  55. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/enumerator.rb +1 -1
  56. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/file.rb +1 -1
  57. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/float.rb +1 -1
  58. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/hash.rb +3 -1
  59. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/integer.rb +1 -1
  60. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/io.rb +1 -1
  61. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/method.rb +1 -1
  62. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/module.rb +1 -1
  63. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/numeric.rb +1 -1
  64. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/proc.rb +1 -1
  65. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/queue.rb +1 -1
  66. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/range.rb +1 -1
  67. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/regexp.rb +1 -1
  68. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/string.rb +3 -1
  69. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/struct.rb +1 -1
  70. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/symbol.rb +1 -1
  71. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/time.rb +1 -1
  72. data/lib/kind/{core/type_checkers → objects/modules}/custom/boolean.rb +2 -2
  73. data/lib/kind/{core/type_checkers → objects/modules}/custom/callable.rb +1 -1
  74. data/lib/kind/{core/type_checkers → objects/modules}/custom/lambda.rb +1 -1
  75. data/lib/kind/{core/type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
  76. data/lib/kind/{core/type_checkers → objects/modules}/stdlib/set.rb +3 -1
  77. data/lib/kind/objects/nil.rb +17 -0
  78. data/lib/kind/objects/not_nil.rb +9 -0
  79. data/lib/kind/objects/object.rb +56 -0
  80. data/lib/kind/objects/respond_to.rb +30 -0
  81. data/lib/kind/objects/union_type.rb +44 -0
  82. data/lib/kind/{core/presence.rb → presence.rb} +4 -2
  83. data/lib/kind/result.rb +31 -0
  84. data/lib/kind/result/abstract.rb +53 -0
  85. data/lib/kind/result/failure.rb +33 -0
  86. data/lib/kind/result/methods.rb +17 -0
  87. data/lib/kind/result/monad.rb +74 -0
  88. data/lib/kind/result/monad/wrapper.rb +19 -0
  89. data/lib/kind/result/success.rb +53 -0
  90. data/lib/kind/strict/disabled.rb +34 -0
  91. data/lib/kind/try.rb +46 -0
  92. data/lib/kind/validator.rb +14 -10
  93. data/lib/kind/version.rb +1 -1
  94. metadata +91 -49
  95. data/lib/kind/core.rb +0 -15
  96. data/lib/kind/core/error.rb +0 -15
  97. data/lib/kind/core/maybe.rb +0 -42
  98. data/lib/kind/core/maybe/none.rb +0 -57
  99. data/lib/kind/core/maybe/result.rb +0 -51
  100. data/lib/kind/core/maybe/some.rb +0 -90
  101. data/lib/kind/core/maybe/typed.rb +0 -29
  102. data/lib/kind/core/try.rb +0 -34
  103. data/lib/kind/core/type_checker.rb +0 -87
  104. data/lib/kind/core/type_checkers.rb +0 -30
  105. data/lib/kind/core/utils/kind.rb +0 -61
  106. data/lib/kind/core/utils/undefined.rb +0 -7
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class None < Monad
6
+ def value_or(default = UNDEFINED, &block)
7
+ Error.invalid_default_arg! if UNDEFINED == default && !block
8
+
9
+ UNDEFINED != default ? default : block.call
10
+ end
11
+
12
+ def none?; true; end
13
+
14
+ def map(_method_name = UNDEFINED, &fn)
15
+ self
16
+ end
17
+
18
+ alias_method :map!, :map
19
+ alias_method :then, :map
20
+ alias_method :then!, :map
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!
26
+
27
+ def try!(method_name = UNDEFINED, *args, &block)
28
+ STRICT.kind_of(::Symbol, method_name)if UNDEFINED != method_name
29
+
30
+ self
31
+ end
32
+
33
+ alias_method :try, :try!
34
+
35
+ def dig(*keys)
36
+ self
37
+ end
38
+
39
+ def presence
40
+ self
41
+ end
42
+
43
+ def inspect
44
+ '#<%s value=%s>' % ['Kind::None', value.inspect]
45
+ end
46
+ end
47
+
48
+ NONE_INSTANCE = None.new(nil)
49
+ end
50
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/dig'
4
+ require 'kind/presence'
5
+
6
+ module Kind
7
+ module Maybe
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)
20
+ @value
21
+ end
22
+
23
+ def none?; false; end
24
+
25
+ def map(method_name = UNDEFINED, &fn)
26
+ map!(method_name, &fn)
27
+ rescue StandardError => exception
28
+ None.new(exception)
29
+ end
30
+
31
+ alias_method :then, :map
32
+ alias_method :and_then, :map
33
+
34
+ def map!(method_name = UNDEFINED, &fn)
35
+ result = if UNDEFINED != method_name
36
+ return NONE_INSTANCE unless @value.respond_to?(KindSymbol[method_name])
37
+
38
+ @value.public_send(method_name)
39
+ else
40
+ fn.call(@value)
41
+ end
42
+
43
+ resolve(result)
44
+ end
45
+
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
78
+
79
+ def try!(method_name = UNDEFINED, *args, &block)
80
+ return __try_block__(block, args) if block
81
+
82
+ return __try_method__(method_name, args) if UNDEFINED != method_name
83
+
84
+ raise ArgumentError, 'method name or a block must be present'
85
+ end
86
+
87
+ def try(method_name = UNDEFINED, *args, &block)
88
+ return __try_block__(block, args) if block
89
+
90
+ return __try_method__(method_name, args) if value.respond_to?(method_name)
91
+
92
+ NONE_INSTANCE
93
+ rescue TypeError
94
+ NONE_INSTANCE
95
+ end
96
+
97
+ def dig(*keys)
98
+ resolve(Dig.call!(value, keys))
99
+ end
100
+
101
+ def presence
102
+ resolve(Presence.(value))
103
+ end
104
+
105
+ def inspect
106
+ '#<%s value=%s>' % ['Kind::Some', value.inspect]
107
+ end
108
+
109
+ private
110
+
111
+ def __try_method__(method_name, args)
112
+ __try_block__(KindSymbol[method_name].to_proc, args)
113
+ end
114
+
115
+ def __try_block__(block, args)
116
+ result = args.empty? ? block.call(value) : block.call(*args.unshift(value))
117
+
118
+ resolve(result)
119
+ end
120
+
121
+ def resolve(result)
122
+ return result if Maybe::None === result
123
+ return NONE_INSTANCE if KIND.nil_or_undefined?(result)
124
+ return None.new(result) if ::Exception === result
125
+
126
+ Some.new(result)
127
+ end
128
+
129
+ private_constant :KindSymbol, :VALUE_CANT_BE_NONE
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Maybe
5
+ class Typed
6
+ include Wrapper
7
+
8
+ singleton_class.send(:alias_method, :[], :new)
9
+
10
+ def initialize(kind)
11
+ @kind = kind
12
+ end
13
+
14
+ def new(arg)
15
+ value = Monad::Value[arg]
16
+
17
+ @kind === value ? Maybe::Some[value] : Maybe::NONE_INSTANCE
18
+ end
19
+
20
+ alias_method :[], :new
21
+
22
+ def inspect
23
+ "Kind::Maybe<#{@kind}>"
24
+ end
25
+
26
+ private
27
+
28
+ def __call_before_expose_the_arg_in_a_block(arg)
29
+ value = Monad::Value[arg]
30
+
31
+ @kind === value ? value : Maybe::NONE_INSTANCE
32
+ end
33
+ end
34
+ end
35
+ 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)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Class
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Class; end
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Comparable
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Comparable; end
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Enumerable
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Enumerable; end
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Enumerator
5
- extend self, TypeChecker
5
+ extend self, ::Kind::Object
6
6
 
7
7
  def kind; ::Enumerator; end
8
8
  end