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
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  <p align="center">
2
2
  <h1 align="center">🤷 kind</h1>
3
- <p align="center"><i>A simple type system (at runtime) for Ruby - free of dependencies.</i></p>
4
- <br>
3
+ <p align="center"><i>A development toolkit for Ruby with several small/cohesive abstractions to empower your development workflow - It's totally free of dependencies.</i></p>
5
4
  </p>
6
5
 
7
6
  <p align="center">
@@ -9,16 +8,18 @@
9
8
  <img alt="Gem" src="https://img.shields.io/gem/v/kind.svg?style=flat-square">
10
9
  </a>
11
10
 
12
- <img src="https://img.shields.io/badge/ruby%20%3E=%202.1.0,%20%3C%203.1-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
13
-
14
- <img src="https://img.shields.io/badge/rails%20%3E=%203.2.0,%20%3C%207-rails.svg?colorA=8B0000&colorB=FF0000" alt="Rails">
15
-
16
- <br />
17
-
18
11
  <a href="https://travis-ci.com/serradura/kind">
19
12
  <img alt="Build Status" src="https://travis-ci.com/serradura/kind.svg?branch=master">
20
13
  </a>
21
14
 
15
+ <br />
16
+
17
+ <img src="https://img.shields.io/badge/ruby%20%3E=%202.1,%20%3C%203.1-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
18
+
19
+ <img src="https://img.shields.io/badge/rails%20%3E=%203.2.0,%20%3C%207.0-rails.svg?colorA=8B0000&colorB=FF0000" alt="Rails">
20
+
21
+ <br />
22
+
22
23
  <a href="https://codeclimate.com/github/serradura/kind/maintainability">
23
24
  <img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/711329decb2806ccac95/maintainability">
24
25
  </a>
@@ -30,20 +31,22 @@
30
31
 
31
32
  **Motivation:**
32
33
 
33
- As a creator of Ruby gems, I have a common need that I have to handle in many of my projects: type checking of method arguments.
34
+ This project was born to help me with a simple task, create a light and fast type checker (at runtime) for Ruby. The initial idea was to have something to raise an exception when a method or function (procs) received a wrong input.
35
+
36
+ But through time it was natural the addition of more features to improve the development workflow, like monads ([`Kind::Maybe`](#kindmaybe), `Kind::Either` / `Kind::Result`), enums (`Kind::Enum`), immutable objects (`Kind::ImmutableAttributes`), [type validation via ActiveModel::Validation](#kindvalidator-activemodelvalidations), and several abstractions to help the implementation of business logic (`Kind::Functional::Steps`, `Kind::Functional::Action`, `Kind::Action`).
34
37
 
35
- One of the goals of this project is to do simple type checking like `"some string".is_a?(String)`, but, exposing useful abstractions around this. e.g: [Kind.\<Type\> methods](#verifying-the-kind-of-some-object), [active model validations](#kindvalidator-activemodelvalidations), [maybe monad](#kindmaybe).
38
+ So, I invite you to check out these features to see how they could be useful for you. Enjoy!
36
39
 
37
40
  ## Documentation <!-- omit in toc -->
38
41
 
39
42
  Version | Documentation
40
43
  ---------- | -------------
41
- unreleased | https://github.com/serradura/u-case/blob/main/README.md
42
- 5.1.0 | https://github.com/serradura/u-case/blob/v5.x/README.md
43
- 4.1.0 | https://github.com/serradura/u-case/blob/v4.x/README.md
44
- 3.1.0 | https://github.com/serradura/u-case/blob/v3.x/README.md
45
- 2.3.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
46
- 1.9.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
44
+ unreleased | https://github.com/serradura/kind/blob/main/README.md
45
+ 5.5.0 | https://github.com/serradura/kind/blob/v5.x/README.md
46
+ 4.1.0 | https://github.com/serradura/kind/blob/v4.x/README.md
47
+ 3.1.0 | https://github.com/serradura/kind/blob/v3.x/README.md
48
+ 2.3.0 | https://github.com/serradura/kind/blob/v2.x/README.md
49
+ 1.9.0 | https://github.com/serradura/kind/blob/v1.x/README.md
47
50
 
48
51
  ## Table of Contents <!-- omit in toc -->
49
52
  - [Compatibility](#compatibility)
@@ -58,16 +61,16 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
58
61
  - [Kind::\<Type\>.value()](#kindtypevalue-1)
59
62
  - [Kind::\<Type\>.maybe](#kindtypemaybe)
60
63
  - [Kind::\<Type\>?](#kindtype-2)
61
- - [Kind::{Array,Hash,String,Set}.value_or_empty()](#kindarrayhashstringsetvalue_or_empty)
62
- - [List of all type checkers](#list-of-all-type-checkers)
64
+ - [Kind::{Array,Hash,String,Set}.empty_or()](#kindarrayhashstringsetempty_or)
65
+ - [List of all type handlers](#list-of-all-type-handlers)
63
66
  - [Core](#core)
64
67
  - [Stdlib](#stdlib)
65
68
  - [Custom](#custom)
66
- - [Creating type checkers](#creating-type-checkers)
69
+ - [Creating type handlers](#creating-type-handlers)
67
70
  - [Dynamic creation](#dynamic-creation)
68
71
  - [Using a class or a module](#using-a-class-or-a-module)
69
72
  - [Using an object which responds to ===](#using-an-object-which-responds-to-)
70
- - [Kind::<Type> module](#kindtype-module)
73
+ - [Kind::<Type> object](#kindtype-object)
71
74
  - [Utility methods](#utility-methods)
72
75
  - [Kind.of_class?()](#kindof_class)
73
76
  - [Kind.of_module?()](#kindof_module)
@@ -119,14 +122,14 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
119
122
 
120
123
  ## Compatibility
121
124
 
122
- | u-case | branch | ruby | activemodel |
123
- | -------------- | ------- | -------- | -------------- |
124
- | unreleased | main | >= 2.1.0 | >= 3.2, <= 6.1 |
125
- | 5.1.0 | v5.x | >= 2.1.0 | >= 3.2, <= 6.1 |
126
- | 4.1.0 | v4.x | >= 2.2.0 | >= 3.2, <= 6.1 |
127
- | 3.1.0 | v3.x | >= 2.2.0 | >= 3.2, <= 6.1 |
128
- | 2.3.0 | v2.x | >= 2.2.0 | >= 3.2, <= 6.0 |
129
- | 1.9.0 | v1.x | >= 2.2.0 | >= 3.2, <= 6.0 |
125
+ | kind | branch | ruby | activemodel |
126
+ | -------------- | ------- | ------------------ | -------------- |
127
+ | unreleased | main | >= 2.1.0, <= 3.0.0 | >= 3.2, < 7.0 |
128
+ | 5.5.0 | v5.x | >= 2.1.0, <= 3.0.0 | >= 3.2, < 7.0 |
129
+ | 4.1.0 | v4.x | >= 2.2.0, <= 3.0.0 | >= 3.2, < 7.0 |
130
+ | 3.1.0 | v3.x | >= 2.2.0, <= 2.7 | >= 3.2, < 7.0 |
131
+ | 2.3.0 | v2.x | >= 2.2.0, <= 2.7 | >= 3.2, <= 6.0 |
132
+ | 1.9.0 | v1.x | >= 2.2.0, <= 2.7 | >= 3.2, <= 6.0 |
130
133
 
131
134
  > Note: The activemodel is an optional dependency, it is related with the [Kind::Validator](#kindvalidator-activemodelvalidations).
132
135
 
@@ -327,17 +330,17 @@ collection.select(&Kind::Enumerable?) # [{:number=>1}, {:number=>3}, [:number, 5
327
330
 
328
331
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
329
332
 
330
- ### Kind::{Array,Hash,String,Set}.value_or_empty()
333
+ ### Kind::{Array,Hash,String,Set}.empty_or()
331
334
 
332
- This method is available for some type checkers (`Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set`), and it will return an empty frozen value if the given one hasn't the expected kind.
335
+ This method is available for some type handlers (`Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set`), and it will return an empty frozen value if the given one hasn't the expected kind.
333
336
  ```ruby
334
- Kind::Array.value_or_empty({}) # []
335
- Kind::Array.value_or_empty({}).frozen? # true
337
+ Kind::Array.empty_or({}) # []
338
+ Kind::Array.empty_or({}).frozen? # true
336
339
  ```
337
340
 
338
341
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
339
342
 
340
- ### List of all type checkers
343
+ ### List of all type handlers
341
344
 
342
345
  #### Core
343
346
 
@@ -376,9 +379,9 @@ Kind::Array.value_or_empty({}).frozen? # true
376
379
 
377
380
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
378
381
 
379
- ### Creating type checkers
382
+ ### Creating type handlers
380
383
 
381
- There are two ways to do this, you can create type checkers dynamically or defining a module.
384
+ There are two ways to do this, you can create type handlers dynamically or defining a module.
382
385
 
383
386
  #### Dynamic creation
384
387
 
@@ -394,7 +397,7 @@ kind_of_user = Kind::Of(User)
394
397
 
395
398
  # kind_of_user.name
396
399
  # kind_of_user.kind
397
- # The type checker can return its kind and its name
400
+ # The type handler can return its kind and its name
398
401
  kind_of_user.name # "User"
399
402
  kind_of_user.kind # User
400
403
 
@@ -464,7 +467,7 @@ PositiveInteger = Kind::Of(
464
467
 
465
468
  # PositiveInteger.name
466
469
  # PositiveInteger.kind
467
- # The type checker can return its kind and its name
470
+ # The type handler can return its kind and its name
468
471
  PositiveInteger.name # "PositiveInteger"
469
472
  PositiveInteger.kind # #<Proc:0x0000.... >
470
473
 
@@ -525,9 +528,9 @@ PositiveInteger.maybe(2).value_or(1) # 2
525
528
 
526
529
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
527
530
 
528
- #### Kind::<Type> module
531
+ #### Kind::<Type> object
529
532
 
530
- The idea here is to create a type checker inside of the `Kind` namespace, so to do this, you will only need to use pure Ruby. e.g:
533
+ The idea here is to create a type handler inside of the `Kind` namespace and to do this you will only need to use pure Ruby. e.g:
531
534
 
532
535
  ```ruby
533
536
  class User
@@ -535,9 +538,9 @@ end
535
538
 
536
539
  module Kind
537
540
  module User
538
- extend self, TypeChecker
541
+ extend self, ::Kind::Object
539
542
 
540
- # Define the expected kind of this type checker.
543
+ # Define the expected kind of this type handler.
541
544
  def kind; ::User; end
542
545
  end
543
546
 
@@ -547,7 +550,7 @@ module Kind
547
550
  end
548
551
  end
549
552
 
550
- # Doing this you will have the same methods of a standard type checker (like: `Kind::Symbol`).
553
+ # Doing this you will have the same methods of a standard type handler (like: `Kind::Symbol`).
551
554
 
552
555
  user = User.new
553
556
 
@@ -565,7 +568,7 @@ The advantages of this approach are:
565
568
 
566
569
  The disadvantage is:
567
570
 
568
- 1. You could overwrite some standard type checker or constant. I believe that this will be hard to happen, but must be your concern if you decide to use this kind of approach.
571
+ 1. You could overwrite some standard type handler or constant. I believe that this will be hard to happen, but must be your concern if you decide to use this kind of approach.
569
572
 
570
573
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
571
574
 
@@ -1459,7 +1462,7 @@ Follows the list of constants if the alias was defined:
1459
1462
 
1460
1463
  ## Kind::Validator (ActiveModel::Validations)
1461
1464
 
1462
- This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 6.1.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
1465
+ This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 7.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
1463
1466
 
1464
1467
  ```ruby
1465
1468
  class Person
@@ -1497,7 +1500,7 @@ Use an array to verify if the attribute is an instance of one of the classes/mod
1497
1500
  validates :status, kind: { of: [String, Symbol]}
1498
1501
  ```
1499
1502
 
1500
- Because of kind verification be made via `===` you can use type checkers as the expected kinds.
1503
+ Because of kind verification be made via `===` you can use type handlers as the expected kinds.
1501
1504
 
1502
1505
  ```ruby
1503
1506
  validates :alive, kind: Kind::Boolean
data/kind.gemspec CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ['Rodrigo Serradura']
7
7
  spec.email = ['rodrigo.serradura@gmail.com']
8
8
 
9
- spec.summary = %q{A simple type system (at runtime) for Ruby.}
10
- spec.description = %q{A simple type system (at runtime) for Ruby - free of dependencies.}
9
+ spec.summary = %q{A development toolkit for Ruby with several small/cohesive abstractions to empower your development workflow.}
10
+ spec.description = %q{A development toolkit for Ruby with several small/cohesive abstractions (monads, enums, business logic, data validation...) to empower your development workflow - It's totally free of dependencies.}
11
11
  spec.homepage = 'https://github.com/serradura/kind'
12
12
  spec.license = 'MIT'
13
13
  spec.required_ruby_version = Gem::Requirement.new('>= 2.1.0')
data/lib/kind.rb CHANGED
@@ -1,51 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'ostruct'
5
-
6
- module Kind
7
- require 'kind/version'
8
- require 'kind/core'
9
-
10
- extend self
11
-
12
- def is?(kind, arg)
13
- KIND.is?(kind, arg)
14
- end
15
-
16
- alias is is?
17
-
18
- def of?(kind, *args)
19
- KIND.of?(kind, args)
20
- end
21
-
22
- def of_class?(value)
23
- KIND.of_class?(value)
24
- end
25
-
26
- def of_module?(value)
27
- KIND.of_module?(value)
28
- end
29
-
30
- def respond_to(value, *method_names)
31
- method_names.each { |method_name| KIND.respond_to!(method_name, value) }
32
-
33
- value
34
- end
35
-
36
- def of_module_or_class(value)
37
- KIND.of_module_or_class!(value)
38
- end
39
-
40
- def of(kind, object)
41
- KIND.of!(kind, object)
42
- end
43
-
44
- def value(kind, value, default:)
45
- KIND.value(kind, value, of(kind, default))
46
- end
47
-
48
- def Of(kind, opt = Empty::HASH)
49
- TypeChecker::Object.new(kind, opt)
50
- end
51
- end
3
+ require 'kind/basic'
4
+ require 'kind/objects'
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module ACTION_STEPS
5
+ private
6
+
7
+ def Check(mthod); ->(value) { __Check(thod, value) }; end
8
+ def Step(mthod); ->(value) { __Step(mthod, value) }; end
9
+ def Map(mthod); ->(value) { __Map(mthod, value) }; end
10
+ def Tee(mthod); ->(value) { __Tee(mthod, value) }; end
11
+ def Try(mthod, opt = Empty::HASH)
12
+ ->(value) { __Try(mthod, value, opt) }
13
+ end
14
+
15
+ def Check!(mthod, value); __Check(mthod, value); end
16
+ def Step!(mthod, value); __Step(mthod, value); end
17
+ def Map!(mthod, value); __Map(mthod, value); end
18
+ def Tee!(mthod, value); __Tee(mthod, value); end
19
+ def Try!(mthod, value, opt = Empty::HASH); __Try(mthod, value, opt); end
20
+
21
+ def __Check(mthod, value) # :nodoc:
22
+ __resolve_step(mthod, value) ? Success(mthod, value) : Failure(mthod, value)
23
+ end
24
+
25
+ def __Step(mthod, value) # :nodoc:
26
+ __resolve_step(mthod, value)
27
+ end
28
+
29
+ def __Map(mthod, value) # :nodoc:
30
+ Success(mthod, __resolve_step(mthod, value))
31
+ end
32
+
33
+ def __Tee(mthod, value) # :nodoc:
34
+ __resolve_step(mthod, value)
35
+
36
+ Success(mthod, value)
37
+ end
38
+
39
+ def __Try(mthod, value, opt = Empty::HASH) # :nodoc:
40
+ begin
41
+ Success(mthod, __resolve_step(mthod, value))
42
+ rescue opt.fetch(:catch, StandardError) => e
43
+ Failure(mthod, __map_step_exception(e))
44
+ end
45
+ end
46
+
47
+ def __resolve_step(mthod, value) # :nodoc:
48
+ send(mthod, value)
49
+ end
50
+
51
+ def __map_step_exception(value) # :nodoc:
52
+ value
53
+ end
54
+ end
55
+
56
+ private_constant :ACTION_STEPS
57
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/__lib__/kind'
4
+ require 'kind/__lib__/undefined'
5
+
6
+ module Kind
7
+ module ATTRIBUTES
8
+ extend self
9
+
10
+ def name!(name)
11
+ STRICT.kind_of(::Symbol, name)
12
+ end
13
+
14
+ def value(kind, default, visibility = :private)
15
+ [kind, default, visibility]
16
+ end
17
+
18
+ def value_to_assign(kind, default, hash, name)
19
+ raw_value = hash[name]
20
+
21
+ return raw_value if kind.nil? && UNDEFINED == default
22
+
23
+ value = resolve_value_to_assign(kind, default, raw_value)
24
+
25
+ (kind.nil? || kind === value) ? value : nil
26
+ end
27
+
28
+ def value!(kind, default)
29
+ return value(kind, default) unless kind.nil?
30
+
31
+ raise Error.new("kind expected to not be nil")
32
+ end
33
+
34
+ def value_to_assign!(kind, default, hash, name)
35
+ value = resolve_value_to_assign(kind, default, hash[name])
36
+
37
+ Kind.of(kind, value, label: name)
38
+ end
39
+
40
+ private
41
+
42
+ def resolve_value_to_assign(kind, default, value)
43
+ if kind == ::Proc
44
+ UNDEFINED == default ? value : KIND.value(kind, value, default)
45
+ else
46
+ default_is_a_callable = default.respond_to?(:call)
47
+
48
+ default_value =
49
+ if default_is_a_callable
50
+ default_fn = Proc === default ? default : default.method(:call)
51
+
52
+ default_fn.arity != 0 ? default_fn.call(value) : default_fn.call
53
+ else
54
+ default
55
+ end
56
+
57
+ return value if UNDEFINED == default_value
58
+ return default_value || value if kind.nil?
59
+
60
+ default_is_a_callable ? KIND.value(kind, default_value, value) : KIND.value(kind, value, default_value)
61
+ end
62
+ end
63
+ end
64
+
65
+ private_constant :ATTRIBUTES
66
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/__lib__/strict'
4
+
5
+ module Kind
6
+ module KIND
7
+ extend self
8
+
9
+ def nil_or_undefined?(value) # :nodoc:
10
+ value.nil? || Undefined == value
11
+ end
12
+
13
+ def of?(kind, values) # :nodoc:
14
+ of_kind = -> value { kind === value }
15
+
16
+ values.empty? ? of_kind : values.all?(&of_kind)
17
+ end
18
+
19
+ def respond_to!(method_name, value) # :nodoc:
20
+ return value if value.respond_to?(method_name)
21
+
22
+ raise Error.new("expected #{value} to respond to :#{method_name}")
23
+ end
24
+
25
+ def interface?(method_names, value) # :nodoc:
26
+ method_names.all? { |method_name| value.respond_to?(method_name) }
27
+ end
28
+
29
+ def value(kind, arg, default) # :nodoc:
30
+ kind === arg ? arg : default
31
+ end
32
+
33
+ def is?(expected, value) # :nodoc:
34
+ is(STRICT.module_or_class(expected), value)
35
+ end
36
+
37
+ private
38
+
39
+ def is(expected_kind, value) # :nodoc:
40
+ kind = STRICT.module_or_class(value)
41
+
42
+ if OF.class?(kind)
43
+ kind <= expected_kind || expected_kind == ::Class
44
+ else
45
+ kind == expected_kind || kind.kind_of?(expected_kind)
46
+ end
47
+ end
48
+ end
49
+
50
+ private_constant :KIND
51
+ end