kind 4.0.0 → 5.3.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.
- checksums.yaml +4 -4
 - data/.tool-versions +1 -1
 - data/.travis.sh +39 -7
 - data/.travis.yml +1 -2
 - data/CHANGELOG.md +486 -28
 - data/Gemfile +13 -6
 - data/README.md +153 -49
 - data/kind.gemspec +1 -1
 - data/lib/kind.rb +2 -84
 - data/lib/kind/__lib__/action_steps.rb +57 -0
 - data/lib/kind/__lib__/attributes.rb +66 -0
 - data/lib/kind/__lib__/kind.rb +51 -0
 - data/lib/kind/__lib__/of.rb +17 -0
 - data/lib/kind/__lib__/strict.rb +49 -0
 - data/lib/kind/__lib__/undefined.rb +14 -0
 - data/lib/kind/action.rb +127 -0
 - data/lib/kind/active_model/validation.rb +3 -4
 - data/lib/kind/basic.rb +79 -0
 - data/lib/kind/basic/error.rb +29 -0
 - data/lib/kind/{undefined.rb → basic/undefined.rb} +6 -1
 - data/lib/kind/dig.rb +21 -5
 - data/lib/kind/either.rb +30 -0
 - data/lib/kind/either/left.rb +29 -0
 - data/lib/kind/either/methods.rb +17 -0
 - data/lib/kind/either/monad.rb +65 -0
 - data/lib/kind/either/monad/wrapper.rb +19 -0
 - data/lib/kind/either/right.rb +38 -0
 - data/lib/kind/empty.rb +2 -2
 - data/lib/kind/empty/constant.rb +7 -0
 - data/lib/kind/enum.rb +63 -0
 - data/lib/kind/enum/item.rb +40 -0
 - data/lib/kind/enum/methods.rb +72 -0
 - data/lib/kind/function.rb +45 -0
 - data/lib/kind/functional.rb +89 -0
 - data/lib/kind/functional/action.rb +90 -0
 - data/lib/kind/immutable_attributes.rb +34 -0
 - data/lib/kind/immutable_attributes/initializer.rb +70 -0
 - data/lib/kind/immutable_attributes/reader.rb +38 -0
 - data/lib/kind/maybe.rb +37 -12
 - data/lib/kind/maybe/methods.rb +21 -0
 - data/lib/kind/maybe/monad.rb +82 -0
 - data/lib/kind/maybe/monad/wrapper.rb +19 -0
 - data/lib/kind/maybe/none.rb +12 -19
 - data/lib/kind/maybe/some.rb +68 -26
 - data/lib/kind/maybe/typed.rb +11 -5
 - data/lib/kind/maybe/{wrappable.rb → wrapper.rb} +9 -7
 - data/lib/kind/monad.rb +22 -0
 - data/lib/kind/monads.rb +5 -0
 - data/lib/kind/objects.rb +17 -0
 - data/lib/kind/objects/basic_object.rb +43 -0
 - data/lib/kind/objects/modules.rb +32 -0
 - data/lib/kind/{type_checkers → objects/modules}/core/array.rb +3 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/class.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/comparable.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/enumerable.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/enumerator.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/file.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/float.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/hash.rb +3 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/integer.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/io.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/method.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/module.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/numeric.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/proc.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/queue.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/range.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/regexp.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/string.rb +3 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/struct.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/symbol.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/core/time.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/custom/boolean.rb +2 -2
 - data/lib/kind/{type_checkers → objects/modules}/custom/callable.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/custom/lambda.rb +1 -1
 - data/lib/kind/{type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
 - data/lib/kind/{type_checkers → objects/modules}/stdlib/set.rb +3 -1
 - data/lib/kind/objects/nil.rb +17 -0
 - data/lib/kind/objects/not_nil.rb +9 -0
 - data/lib/kind/objects/object.rb +56 -0
 - data/lib/kind/objects/respond_to.rb +30 -0
 - data/lib/kind/objects/union_type.rb +44 -0
 - data/lib/kind/presence.rb +4 -2
 - data/lib/kind/result.rb +31 -0
 - data/lib/kind/result/abstract.rb +53 -0
 - data/lib/kind/result/failure.rb +33 -0
 - data/lib/kind/result/methods.rb +17 -0
 - data/lib/kind/result/monad.rb +74 -0
 - data/lib/kind/result/monad/wrapper.rb +19 -0
 - data/lib/kind/result/success.rb +53 -0
 - data/lib/kind/strict/disabled.rb +34 -0
 - data/lib/kind/try.rb +21 -11
 - data/lib/kind/validator.rb +111 -0
 - data/lib/kind/version.rb +1 -1
 - metadata +78 -48
 - data/lib/kind/active_model/kind_validator.rb +0 -96
 - data/lib/kind/core.rb +0 -9
 - data/lib/kind/core/deprecation.rb +0 -29
 - data/lib/kind/core/kind.rb +0 -61
 - data/lib/kind/core/undefined.rb +0 -7
 - data/lib/kind/deprecations/built_in_type_checkers.rb +0 -23
 - data/lib/kind/deprecations/checker.rb +0 -16
 - data/lib/kind/deprecations/checker/factory.rb +0 -31
 - data/lib/kind/deprecations/checker/protocol.rb +0 -73
 - data/lib/kind/deprecations/is.rb +0 -35
 - data/lib/kind/deprecations/of.rb +0 -258
 - data/lib/kind/deprecations/types.rb +0 -121
 - data/lib/kind/error.rb +0 -15
 - data/lib/kind/maybe/result.rb +0 -51
 - data/lib/kind/type_checker.rb +0 -73
 - data/lib/kind/type_checkers.rb +0 -30
 
| 
         @@ -1,7 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
      
 3 
     | 
    
         
            +
            warn '[DEPRECATION] "kind/active_model/validation" is deprecated; use "kind/validator" instead. ' \
         
     | 
| 
      
 4 
     | 
    
         
            +
                'It will be removed on next major release.'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
       4 
6 
     | 
    
         
             
            require 'kind/validator'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'active_model'
         
     | 
| 
       6 
     | 
    
         
            -
            require 'active_model/validations'
         
     | 
| 
       7 
     | 
    
         
            -
            require_relative 'kind_validator'
         
     | 
    
        data/lib/kind/basic.rb
    ADDED
    
    | 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kind/__lib__/kind'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'kind/__lib__/undefined'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'kind/basic/undefined'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'kind/basic/error'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 12 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def is?(kind, arg)
         
     | 
| 
      
 15 
     | 
    
         
            +
                KIND.is?(kind, arg)
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def is(*args)
         
     | 
| 
      
 19 
     | 
    
         
            +
                warn '[DEPRECATION] Kind.is will behave like Kind.is! in the next major release; ' \
         
     | 
| 
      
 20 
     | 
    
         
            +
                    'use Kind.is? instead.'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                is?(*args)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              def is!(kind, arg, label: nil)
         
     | 
| 
      
 26 
     | 
    
         
            +
                return arg if KIND.is?(kind, arg)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                label_text = label ? "#{label}: " : ''
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                raise Kind::Error.new("#{label_text}#{arg} expected to be a #{kind}")
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def of?(kind, *args)
         
     | 
| 
      
 34 
     | 
    
         
            +
                KIND.of?(kind, args)
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              def of_class?(value)
         
     | 
| 
      
 38 
     | 
    
         
            +
                OF.class?(value)
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def of_module?(value)
         
     | 
| 
      
 42 
     | 
    
         
            +
                OF.module?(value)
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def respond_to?(value, *method_names)
         
     | 
| 
      
 46 
     | 
    
         
            +
                return super(value) if method_names.empty?
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                KIND.interface?(method_names, value)
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def of(kind, value, label: nil)
         
     | 
| 
      
 52 
     | 
    
         
            +
                STRICT.object_is_a(kind, value, label)
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              alias_method :of!, :of
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              def of_class(value)
         
     | 
| 
      
 58 
     | 
    
         
            +
                STRICT.class!(value)
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              def of_module(value)
         
     | 
| 
      
 62 
     | 
    
         
            +
                STRICT.module!(value)
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              def of_module_or_class(value)
         
     | 
| 
      
 66 
     | 
    
         
            +
                STRICT.module_or_class(value)
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              def respond_to(value, *method_names)
         
     | 
| 
      
 70 
     | 
    
         
            +
                method_names.each { |method_name| KIND.respond_to!(method_name, value) }
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                value
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
              alias_method :respond_to!, :respond_to
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              def value(kind, value, default:)
         
     | 
| 
      
 77 
     | 
    
         
            +
                KIND.value(kind, value, of(kind, default))
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Error < StandardError
         
     | 
| 
      
 5 
     | 
    
         
            +
                INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def self.wrong_number_of_args!(given:, expected:)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  raise ArgumentError, "wrong number of arguments (given #{given}, expected #{expected})"
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def self.invalid_default_arg!
         
     | 
| 
      
 12 
     | 
    
         
            +
                  raise ArgumentError, INVALID_DEFAULT_ARG
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(arg, object = UNDEFINED, label: nil)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  if UNDEFINED == object
         
     | 
| 
      
 17 
     | 
    
         
            +
                    # Will be used when the exception was raised with a message. e.g:
         
     | 
| 
      
 18 
     | 
    
         
            +
                    # raise Kind::Error, "some message"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    super(arg)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else
         
     | 
| 
      
 21 
     | 
    
         
            +
                    label_text = label ? "#{label}: " : ''
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    super("#{label_text}#{object.inspect} expected to be a kind of #{arg}")
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                private_constant :INVALID_DEFAULT_ARG
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,9 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       2 
3 
     | 
    
         
             
            module Kind
         
     | 
| 
       3 
4 
     | 
    
         
             
              Undefined = Object.new.tap do |undefined|
         
     | 
| 
       4 
5 
     | 
    
         
             
                def undefined.inspect
         
     | 
| 
       5 
6 
     | 
    
         
             
                  @inspect ||= 'Kind::Undefined'.freeze
         
     | 
| 
       6 
7 
     | 
    
         
             
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
                undefined.inspect
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def undefined.empty?
         
     | 
| 
      
 11 
     | 
    
         
            +
                  true
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
       7 
13 
     | 
    
         | 
| 
       8 
14 
     | 
    
         
             
                def undefined.to_s
         
     | 
| 
       9 
15 
     | 
    
         
             
                  inspect
         
     | 
| 
         @@ -23,7 +29,6 @@ module Kind 
     | 
|
| 
       23 
29 
     | 
    
         
             
                  default.respond_to?(:call) ? default.call : default
         
     | 
| 
       24 
30 
     | 
    
         
             
                end
         
     | 
| 
       25 
31 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                undefined.inspect
         
     | 
| 
       27 
32 
     | 
    
         
             
                undefined.freeze
         
     | 
| 
       28 
33 
     | 
    
         
             
              end
         
     | 
| 
       29 
34 
     | 
    
         
             
            end
         
     | 
    
        data/lib/kind/dig.rb
    CHANGED
    
    | 
         @@ -1,23 +1,39 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/empty'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kind/presence'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       3 
7 
     | 
    
         
             
            module Kind
         
     | 
| 
       4 
8 
     | 
    
         
             
              module Dig
         
     | 
| 
       5 
9 
     | 
    
         
             
                extend self
         
     | 
| 
       6 
10 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                def call(data, keys)
         
     | 
| 
       8 
     | 
    
         
            -
                  return unless keys.is_a?(::Array)
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 11 
     | 
    
         
            +
                def call!(data, keys = Empty::ARRAY) # :nodoc
         
     | 
| 
       10 
12 
     | 
    
         
             
                  keys.reduce(data) do |memo, key|
         
     | 
| 
       11 
13 
     | 
    
         
             
                    value = get(memo, key)
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
                    break if KIND. 
     | 
| 
      
 15 
     | 
    
         
            +
                    break if KIND.nil_or_undefined?(value)
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
       15 
17 
     | 
    
         
             
                    value
         
     | 
| 
       16 
18 
     | 
    
         
             
                  end
         
     | 
| 
       17 
19 
     | 
    
         
             
                end
         
     | 
| 
       18 
20 
     | 
    
         | 
| 
      
 21 
     | 
    
         
            +
                def call(data, *input)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  args = input.size == 1 && input[0].kind_of?(::Array) ? input[0] : input
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  result = call!(data, args)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  return result unless block_given?
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  yield(result) unless KIND.nil_or_undefined?(result)
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def presence(*args, &block)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  Presence.(call(*args, &block))
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       19 
35 
     | 
    
         
             
                def [](*keys)
         
     | 
| 
       20 
     | 
    
         
            -
                  ->(data) { call(data, keys) }
         
     | 
| 
      
 36 
     | 
    
         
            +
                  ->(data) { call!(data, keys) }
         
     | 
| 
       21 
37 
     | 
    
         
             
                end
         
     | 
| 
       22 
38 
     | 
    
         | 
| 
       23 
39 
     | 
    
         
             
                private
         
     | 
    
        data/lib/kind/either.rb
    ADDED
    
    | 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Either
         
     | 
| 
      
 7 
     | 
    
         
            +
                require 'kind/either/monad'
         
     | 
| 
      
 8 
     | 
    
         
            +
                require 'kind/either/left'
         
     | 
| 
      
 9 
     | 
    
         
            +
                require 'kind/either/right'
         
     | 
| 
      
 10 
     | 
    
         
            +
                require 'kind/either/methods'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def new(value)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  Right[value]
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                alias_method :[], :new
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def self.from
         
     | 
| 
      
 21 
     | 
    
         
            +
                  result = yield
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  Either::Monad === result ? result : Either::Right[result]
         
     | 
| 
      
 24 
     | 
    
         
            +
                rescue StandardError => e
         
     | 
| 
      
 25 
     | 
    
         
            +
                  Either::Left[e]
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              extend Either::Methods
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Either::Left < Either::Monad
         
     | 
| 
      
 5 
     | 
    
         
            +
                def left?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  true
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def value_or(default = UNDEFINED, &block)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  Error.invalid_default_arg! if UNDEFINED == default && !block
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  UNDEFINED != default ? default : block.call
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def map(&_)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                alias_method :map!, :map
         
     | 
| 
      
 20 
     | 
    
         
            +
                alias_method :then, :map
         
     | 
| 
      
 21 
     | 
    
         
            +
                alias_method :then!, :map
         
     | 
| 
      
 22 
     | 
    
         
            +
                alias_method :and_then, :map
         
     | 
| 
      
 23 
     | 
    
         
            +
                alias_method :and_then!, :map
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 26 
     | 
    
         
            +
                  '#<%s value=%p>' % ['Kind::Left', value]
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Either::Methods
         
     | 
| 
      
 5 
     | 
    
         
            +
                def Left(value)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  Either::Left[value]
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def Right(value)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  Either::Right[value]
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  base.send(:private, :Left, :Right)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Either::Monad
         
     | 
| 
      
 5 
     | 
    
         
            +
                require 'kind/either/monad/wrapper'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :value
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                singleton_class.send(:alias_method, :[], :new)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(value)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @value = value
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def left?
         
     | 
| 
      
 16 
     | 
    
         
            +
                  false
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def right?
         
     | 
| 
      
 20 
     | 
    
         
            +
                  false
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def value_or(_method_name = UNDEFINED, &block)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  raise NotImplementedError
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def map(&_)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  raise NotImplementedError
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                alias_method :map!, :map
         
     | 
| 
      
 32 
     | 
    
         
            +
                alias_method :then, :map
         
     | 
| 
      
 33 
     | 
    
         
            +
                alias_method :then!, :map
         
     | 
| 
      
 34 
     | 
    
         
            +
                alias_method :and_then, :map
         
     | 
| 
      
 35 
     | 
    
         
            +
                alias_method :and_then!, :map
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def on
         
     | 
| 
      
 38 
     | 
    
         
            +
                  monad = Wrapper.new(self)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  yield(monad)
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  monad.output
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def on_right(matcher = UNDEFINED)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  yield(value) if right? && either?(matcher)
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  self
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def on_left(matcher = UNDEFINED)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  yield(value) if left? && either?(matcher)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  self
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def either?(matcher)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  UNDEFINED == matcher || matcher === value
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def ===(monad)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  self.class === monad && self.value === monad.value
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'kind/monad'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              class Either::Monad::Wrapper < Kind::Monad::Wrapper
         
     | 
| 
      
 7 
     | 
    
         
            +
                def left(matcher = UNDEFINED)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  return if @monad.right? || output?
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  @output = yield(@monad.value) if @monad.either?(matcher)
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def right(matcher = UNDEFINED)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  return if @monad.left? || output?
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  @output = yield(@monad.value) if @monad.either?(matcher)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Either::Right < Either::Monad
         
     | 
| 
      
 5 
     | 
    
         
            +
                def right?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  true
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def value_or(_default = UNDEFINED, &block)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @value
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def map(&fn)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  map!(&fn)
         
     | 
| 
      
 15 
     | 
    
         
            +
                rescue Kind::Monad::Error => e
         
     | 
| 
      
 16 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 17 
     | 
    
         
            +
                rescue StandardError => e
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Either::Left[e]
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def map!(&fn)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  monad = fn.call(@value)
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  return monad if Either::Monad === monad
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  raise Kind::Monad::Error.new('Kind::Right | Kind::Left', monad)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                alias_method :then, :map
         
     | 
| 
      
 30 
     | 
    
         
            +
                alias_method :then!, :map!
         
     | 
| 
      
 31 
     | 
    
         
            +
                alias_method :and_then, :map
         
     | 
| 
      
 32 
     | 
    
         
            +
                alias_method :and_then!, :map!
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 35 
     | 
    
         
            +
                  '#<%s value=%p>' % ['Kind::Right', value]
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/kind/empty.rb
    CHANGED
    
    
    
        data/lib/kind/enum.rb
    ADDED
    
    | 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Enum
         
     | 
| 
      
 8 
     | 
    
         
            +
                require 'kind/enum/item'
         
     | 
| 
      
 9 
     | 
    
         
            +
                require 'kind/enum/methods'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def values(input)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  enum_module = ::Module.new
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  enum_items =
         
     | 
| 
      
 17 
     | 
    
         
            +
                    case input
         
     | 
| 
      
 18 
     | 
    
         
            +
                    when ::Hash then create_from_hash(input)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    when ::Array then create_from_array(input)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    else raise ArgumentError, 'use an array or hash to define a Kind::Enum'
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  enum_items.each { |item| enum_module.const_set(item.name, item) }
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  enum_map = enum_items.each_with_object({}) do |item, memo|
         
     | 
| 
      
 26 
     | 
    
         
            +
                    memo[item.to_s] = item
         
     | 
| 
      
 27 
     | 
    
         
            +
                    memo[item.value] = item
         
     | 
| 
      
 28 
     | 
    
         
            +
                    memo[item.to_sym] = item
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__MAP, enum_map)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__HASH, enum_items.map(&:to_ary).to_h.freeze)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__KEYS, ::Set.new(enum_items.map(&:key)).freeze)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__VALS, ::Set.new(enum_items.map(&:value)).freeze)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__REFS, ::Set.new(enum_map.keys))
         
     | 
| 
      
 36 
     | 
    
         
            +
                  enum_module.const_set(:ENUM__ITEMS, enum_items.freeze)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  enum_module.send(:private_constant, :ENUM__MAP, :ENUM__HASH, :ENUM__KEYS,
         
     | 
| 
      
 39 
     | 
    
         
            +
                                                      :ENUM__VALS, :ENUM__REFS, :ENUM__ITEMS)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  enum_module.module_eval(METHODS)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  enum_module.extend(enum_module)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  enum_module
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                private
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def create_from_hash(input)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    input.map { |key, value| build_item(key, value) }
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def create_from_array(input)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    input.map.with_index { |key, index| build_item(key, index) }
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def build_item(key, value)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    return Item.new(key, value) if key.respond_to?(:to_sym)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    raise ArgumentError, 'use a string or symbol to define a Kind::Enum item'
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     |