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
 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Enum
         
     | 
| 
      
 5 
     | 
    
         
            +
                class Item
         
     | 
| 
      
 6 
     | 
    
         
            +
                  Underscore = ->(arg) do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    str = String(arg).strip
         
     | 
| 
      
 8 
     | 
    
         
            +
                    str.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
         
     | 
| 
      
 9 
     | 
    
         
            +
                    str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
         
     | 
| 
      
 10 
     | 
    
         
            +
                    str.tr!("-", "_")
         
     | 
| 
      
 11 
     | 
    
         
            +
                    str.downcase!
         
     | 
| 
      
 12 
     | 
    
         
            +
                    str
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  attr_reader :value, :to_s, :name, :to_sym, :inspect
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  alias_method :key, :to_s
         
     | 
| 
      
 18 
     | 
    
         
            +
                  alias_method :to_str, :to_s
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(key, val)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @value = val.frozen? ? val : val.dup.freeze
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    @to_s = Kind.respond_to(key, :to_sym).to_s
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @name = Underscore[key].upcase.freeze
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @to_sym = key.to_sym
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @inspect = ('#<Kind::Enum::Item name=%p to_s=%p value=%p>' % [@name, @to_s, @value]).freeze
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def ==(arg)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    arg == value || arg == to_s || arg == to_sym
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def to_ary
         
     | 
| 
      
 34 
     | 
    
         
            +
                    [key, value]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  alias_method :===, :==
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Enum
         
     | 
| 
      
 5 
     | 
    
         
            +
                METHODS = \
         
     | 
| 
      
 6 
     | 
    
         
            +
                <<-RUBY
         
     | 
| 
      
 7 
     | 
    
         
            +
                def to_h
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ENUM__HASH
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def items
         
     | 
| 
      
 12 
     | 
    
         
            +
                  ENUM__ITEMS
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def ===(arg)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ENUM__ITEMS.any? { |item| item === arg }
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def refs
         
     | 
| 
      
 20 
     | 
    
         
            +
                  ENUM__REFS.to_a
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def keys
         
     | 
| 
      
 24 
     | 
    
         
            +
                  ENUM__KEYS.to_a
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def values
         
     | 
| 
      
 28 
     | 
    
         
            +
                  ENUM__VALS.to_a
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def ref?(arg)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  ENUM__REFS.include?(arg)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def key?(arg)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  arg.respond_to?(:to_sym) ? ref?(arg) && !value?(arg) : false
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def value?(arg)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  ENUM__VALS.include?(arg)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def [](arg)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  return arg if ref?(arg)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  raise KeyError, "key or value not found: %p" % [arg]
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def ref(arg)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  arg if ref?(arg)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def item(arg)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  ENUM__MAP[arg]
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def key(arg)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  item(arg).key if value?(arg)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def value_at(arg)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  item(arg).value if key?(arg)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  base.extend(base)
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
                RUBY
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                private_constant :METHODS
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Function
         
     | 
| 
      
 7 
     | 
    
         
            +
                module Behavior
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def self.extended(base)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    base.send(:alias_method, :[], :call)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    base.send(:alias_method, :===, :call)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    base.send(:alias_method, :yield, :call)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def self.included(_)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  raise RuntimeError, "The Kind::Function can't be included, it can be only extended."
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def self.extended(base)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  base.extend(Kind.of_module(base))
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def kind_function!
         
     | 
| 
      
 24 
     | 
    
         
            +
                  return self if Kind.is?(Behavior, self)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  KIND.respond_to!(:call, self).extend(Behavior)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  if method(:call).parameters.empty?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise ArgumentError, "#{self.name}.call must receive at least one argument"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  self.instance_eval(
         
     | 
| 
      
 33 
     | 
    
         
            +
                    'def to_proc; @to_proc ||= method(:call).to_proc; end' \
         
     | 
| 
      
 34 
     | 
    
         
            +
                    "\n" \
         
     | 
| 
      
 35 
     | 
    
         
            +
                    'def curry; @curry ||= to_proc.curry; end'
         
     | 
| 
      
 36 
     | 
    
         
            +
                  )
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  self.to_proc
         
     | 
| 
      
 39 
     | 
    
         
            +
                  self.curry
         
     | 
| 
      
 40 
     | 
    
         
            +
                  self
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                private_constant :Behavior
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,89 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/empty'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kind/__lib__/attributes'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Functional
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.extended(_)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  raise RuntimeError, "The Kind::Functional can't be extended, it can be only included."
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  Kind.of_class(base).send(:extend, ClassMethods)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                module Behavior
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    base.send(:alias_method, :[], :call)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    base.send(:alias_method, :===, :call)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    base.send(:alias_method, :yield, :call)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def initialize(arg = Empty::HASH)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    hash = STRICT.kind_of(::Hash, arg)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    self.class.__dependencies__.each do |name, (kind, default, _visibility)|
         
     | 
| 
      
 28 
     | 
    
         
            +
                      value_to_assign = ATTRIBUTES.value_to_assign!(kind, default, hash, name)
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                      instance_variable_set("@#{name}", value_to_assign)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                module DependencyInjection
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def __dependencies__ # :nodoc:
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @__dependencies__ ||= {}
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def dependency(name, kind, default: UNDEFINED)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    __dependencies__[ATTRIBUTES.name!(name)] = ATTRIBUTES.value!(kind, default)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    attr_reader(name)
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    private(name)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    name
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 52 
     | 
    
         
            +
                  include DependencyInjection
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  def kind_functional!
         
     | 
| 
      
 55 
     | 
    
         
            +
                    return self if Kind.is?(Behavior, self)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    public_methods = self.public_instance_methods - ::Object.new.methods
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    unless public_methods.include?(:call)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      raise Kind::Error.new("expected #{self} to implement `#call`")
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    if public_methods.size > 1
         
     | 
| 
      
 64 
     | 
    
         
            +
                      raise Kind::Error.new("#{self} can only have `#call` as its public method")
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    if public_instance_method(:call).parameters.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                      raise ArgumentError, "#{self.name}#call must receive at least one argument"
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    self.send(:include, Behavior)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    def self.inherited(_)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      raise RuntimeError, "#{self.name} is a Kind::Functional and it can't be inherited by anyone"
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    self.class_eval(
         
     | 
| 
      
 78 
     | 
    
         
            +
                      'def to_proc; @to_proc ||= method(:call).to_proc; end' \
         
     | 
| 
      
 79 
     | 
    
         
            +
                      "\n" \
         
     | 
| 
      
 80 
     | 
    
         
            +
                      'def curry; @curry ||= to_proc.curry; end'
         
     | 
| 
      
 81 
     | 
    
         
            +
                    )
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    __dependencies__.freeze
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    self
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
              end
         
     | 
| 
      
 89 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,90 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/result'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/functional'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kind/__lib__/action_steps'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Functional::Action
         
     | 
| 
      
 9 
     | 
    
         
            +
                CALL_TMPL = [
         
     | 
| 
      
 10 
     | 
    
         
            +
                  'def call(%s)',
         
     | 
| 
      
 11 
     | 
    
         
            +
                  '  result = call!(%s)',
         
     | 
| 
      
 12 
     | 
    
         
            +
                  '',
         
     | 
| 
      
 13 
     | 
    
         
            +
                  '  return result if Kind::Result::Monad === result',
         
     | 
| 
      
 14 
     | 
    
         
            +
                  '',
         
     | 
| 
      
 15 
     | 
    
         
            +
                  '  raise Kind::Error, "#{self.class.name}#call! must return a Kind::Success or Kind::Failure"',
         
     | 
| 
      
 16 
     | 
    
         
            +
                  'end'
         
     | 
| 
      
 17 
     | 
    
         
            +
                ].join("\n").freeze
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                module Macros
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def kind_functional_action!
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return self if Kind.is?(Result::Methods, self)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    public_methods = self.public_instance_methods - ::Object.new.methods
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    unless public_methods.include?(:call!)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      raise Kind::Error.new("expected #{self} to implement `#call!`")
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    if public_methods.size > 1
         
     | 
| 
      
 30 
     | 
    
         
            +
                      raise Kind::Error.new("#{self} can only have `#call!` as its public method")
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    call_parameters = public_instance_method(:call!).parameters
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    if call_parameters.empty?
         
     | 
| 
      
 36 
     | 
    
         
            +
                      raise ArgumentError, "#{self.name}#call! must receive at least one argument"
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    def self.inherited(_)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      raise RuntimeError, "#{self.name} is a Kind::Functional::Action and it can't be inherited"
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    call_parameters.flatten!
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    call_with_args = call_parameters.include?(:req) || call_parameters.include?(:rest)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    call_with_kargs = call_parameters.include?(:keyreq) || call_parameters.include?(:keyrest)
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    call_tmpl_args = '*args, **kargs' if call_with_args && call_with_kargs
         
     | 
| 
      
 49 
     | 
    
         
            +
                    call_tmpl_args = '*args'          if call_with_args && !call_with_kargs
         
     | 
| 
      
 50 
     | 
    
         
            +
                    call_tmpl_args = '**kargs'        if !call_with_args && call_with_kargs
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    self.class_eval(
         
     | 
| 
      
 53 
     | 
    
         
            +
                      "def to_proc; @to_proc ||= method(:call!).to_proc; end" \
         
     | 
| 
      
 54 
     | 
    
         
            +
                      "\n" \
         
     | 
| 
      
 55 
     | 
    
         
            +
                      "def curry; @curry ||= to_proc.curry; end" \
         
     | 
| 
      
 56 
     | 
    
         
            +
                      "\n" \
         
     | 
| 
      
 57 
     | 
    
         
            +
                      "#{CALL_TMPL % [call_tmpl_args, call_tmpl_args]}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                    )
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    if Kind.of_module?(self)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      self.send(:extend, Result::Methods)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      self.send(:extend, ACTION_STEPS)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    else
         
     | 
| 
      
 64 
     | 
    
         
            +
                      self.send(:include, Result::Methods)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      self.send(:include, ACTION_STEPS)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      self.send(:include, Functional::Behavior)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      __dependencies__.freeze
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    self.send(:protected, :call!)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    self
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  Kind.of_class(base).send(:extend, Functional::DependencyInjection)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  base.send(:extend, Macros)
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                def self.extended(base)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  base.send(:extend, Kind.of_module(base))
         
     | 
| 
      
 85 
     | 
    
         
            +
                  base.send(:extend, Macros)
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                private_constant :Macros, :CALL_TMPL
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/__lib__/attributes'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 7 
     | 
    
         
            +
              module ImmutableAttributes
         
     | 
| 
      
 8 
     | 
    
         
            +
                require 'kind/immutable_attributes/initializer'
         
     | 
| 
      
 9 
     | 
    
         
            +
                require 'kind/immutable_attributes/reader'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def __attributes__ # :nodoc:
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @__attributes__ ||= {}
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def attribute(name, kind = nil, default: UNDEFINED, visibility: :public)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    __attributes__[ATTRIBUTES.name!(name)] = ATTRIBUTES.value(kind, default, visibility)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    attr_reader(name)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    private(name) if visibility == :private
         
     | 
| 
      
 22 
     | 
    
         
            +
                    protected(name) if visibility == :protected
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    name
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  base.extend(ClassMethods)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  base.send(:include, Reader)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  base.send(:include, Initializer)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kind/__lib__/attributes'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kind/basic'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kind/empty'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Kind
         
     | 
| 
      
 8 
     | 
    
         
            +
              module ImmutableAttributes
         
     | 
| 
      
 9 
     | 
    
         
            +
                module Initializer
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(arg)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    input = __resolve_attribute_input(arg)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    hash = call_before_initialize_to_prepare_the_input(input)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    @_nil_attrs = ::Set.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @_____attrs = {}
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @attributes = {}
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    self.class.__attributes__.each do |name, (kind, default, visibility)|
         
     | 
| 
      
 20 
     | 
    
         
            +
                      value_to_assign = __resolve_attribute_value_to_assign(kind, default, hash, name)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                      @_nil_attrs << name if value_to_assign.nil?
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @_____attrs[name] = value_to_assign
         
     | 
| 
      
 24 
     | 
    
         
            +
                      @attributes[name] = value_to_assign if visibility == :public
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                      instance_variable_set("@#{name}", value_to_assign)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    @_nil_attrs.freeze
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @attributes.freeze
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    call_after_initialize_and_assign_the_attributes
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def nil_attributes
         
     | 
| 
      
 36 
     | 
    
         
            +
                    @_nil_attrs.to_a
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def nil_attributes?(*names)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    names.empty? ? !@_nil_attrs.empty? : names.all? { |name| @_nil_attrs.include?(name) }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  private
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    def call_before_initialize_to_prepare_the_input(input)
         
     | 
| 
      
 46 
     | 
    
         
            +
                      input
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    def call_after_initialize_and_assign_the_attributes
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    def __resolve_attribute_input(arg)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return arg.attributes if arg.kind_of?(ImmutableAttributes)
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                      arg.kind_of?(::Hash) ? arg : Empty::HASH
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    def __resolve_attribute_value_to_assign(kind, default, hash, name)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      if kind.kind_of?(::Class) && kind < ImmutableAttributes
         
     | 
| 
      
 60 
     | 
    
         
            +
                        kind.new(hash[name])
         
     | 
| 
      
 61 
     | 
    
         
            +
                      elsif kind.kind_of?(::Array) && (nkind = kind[0]).kind_of?(::Class) && nkind < ImmutableAttributes
         
     | 
| 
      
 62 
     | 
    
         
            +
                        Array(hash[name]).map { |item| nkind.new(item) }
         
     | 
| 
      
 63 
     | 
    
         
            +
                      else
         
     | 
| 
      
 64 
     | 
    
         
            +
                        ATTRIBUTES.value_to_assign(kind, default, hash, name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     |