dry-types 1.6.0 → 1.7.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/CHANGELOG.md +20 -0
- data/dry-types.gemspec +3 -5
- data/lib/dry/types/builder.rb +39 -2
- data/lib/dry/types/composition.rb +152 -0
- data/lib/dry/types/container.rb +1 -3
- data/lib/dry/types/extensions/maybe.rb +7 -2
- data/lib/dry/types/extensions/monads.rb +7 -2
- data/lib/dry/types/implication.rb +66 -0
- data/lib/dry/types/intersection.rb +108 -0
- data/lib/dry/types/module.rb +7 -3
- data/lib/dry/types/predicate_registry.rb +7 -20
- data/lib/dry/types/printer/composition.rb +44 -0
- data/lib/dry/types/printer.rb +110 -129
- data/lib/dry/types/sum.rb +3 -91
- data/lib/dry/types/version.rb +1 -1
- data/lib/dry/types.rb +9 -3
- metadata +26 -50
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: fdd7e08f86f3137ead67bb6170e91de625227e97783be335b982e5a4c313b32e
         | 
| 4 | 
            +
              data.tar.gz: faa51ae68eb4942cb64520eed7d6c4dbf5b46af384a91acdfc94105f32298839
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 588feadceca555b168266b6e6ee542d71b154152ea56a88f7b601c33a79b116c90b86356e03bc8ca273e4df5d38e4056277c88502387e836bba4af8409fede14
         | 
| 7 | 
            +
              data.tar.gz: 72326eb3f32d33cbc95d1e20d6bec4f1bc40a66fa6cac818d35b8ff2214d3932f3350d5e6cf36a6a49ea3ffd862d7422a49622d5a98937a0be6f914d0f390965
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,25 @@ | |
| 1 1 | 
             
            <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 1.7.0 2022-11-04
         | 
| 4 | 
            +
             | 
| 5 | 
            +
             | 
| 6 | 
            +
            ### Changed
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            - This version is compatible with recently released dry-rb dependencies (@flash-gordon)
         | 
| 9 | 
            +
            - Updated to dry-core 1.0 (@flash-gordon + @solnic)
         | 
| 10 | 
            +
            - Dependency on dry-container was dropped (@flash-gordon)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            [Compare v1.6.1...v1.7.0](https://github.com/dry-rb/dry-types/compare/v1.6.1...v1.7.0)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            ## 1.6.1 2022-10-15
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
            ### Changed
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            - Fix issues with internal const_missing and Inflector/Module constants (@flash-gordon + @solnic)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            [Compare v1.6.0...v1.6.1](https://github.com/dry-rb/dry-types/compare/v1.6.0...v1.6.1)
         | 
| 22 | 
            +
             | 
| 3 23 | 
             
            ## 1.6.0 2022-10-15
         | 
| 4 24 |  | 
| 5 25 |  | 
    
        data/dry-types.gemspec
    CHANGED
    
    | @@ -30,14 +30,12 @@ Gem::Specification.new do |spec| | |
| 30 30 |  | 
| 31 31 | 
             
              # to update dependencies edit project.yml
         | 
| 32 32 | 
             
              spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
         | 
| 33 | 
            -
              spec.add_runtime_dependency "dry- | 
| 34 | 
            -
              spec.add_runtime_dependency "dry- | 
| 35 | 
            -
              spec.add_runtime_dependency "dry- | 
| 36 | 
            -
              spec.add_runtime_dependency "dry-logic", "~> 1.3", ">= 1.3"
         | 
| 33 | 
            +
              spec.add_runtime_dependency "dry-core", "~> 1.0", "< 2"
         | 
| 34 | 
            +
              spec.add_runtime_dependency "dry-inflector", "~> 1.0", "< 2"
         | 
| 35 | 
            +
              spec.add_runtime_dependency "dry-logic", ">= 1.4", "< 2"
         | 
| 37 36 | 
             
              spec.add_runtime_dependency "zeitwerk", "~> 2.6"
         | 
| 38 37 |  | 
| 39 38 | 
             
              spec.add_development_dependency "bundler"
         | 
| 40 | 
            -
              spec.add_development_dependency "dry-monads", "~> 1.0"
         | 
| 41 39 | 
             
              spec.add_development_dependency "rake"
         | 
| 42 40 | 
             
              spec.add_development_dependency "rspec"
         | 
| 43 41 | 
             
              spec.add_development_dependency "yard"
         | 
    
        data/lib/dry/types/builder.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ module Dry | |
| 5 5 | 
             
                # Common API for building types and composition
         | 
| 6 6 | 
             
                #
         | 
| 7 7 | 
             
                # @api public
         | 
| 8 | 
            +
                # rubocop:disable Metrics/ModuleLength
         | 
| 8 9 | 
             
                module Builder
         | 
| 9 10 | 
             
                  include Dry::Core::Constants
         | 
| 10 11 |  | 
| @@ -30,8 +31,29 @@ module Dry | |
| 30 31 | 
             
                  #
         | 
| 31 32 | 
             
                  # @api private
         | 
| 32 33 | 
             
                  def |(other)
         | 
| 33 | 
            -
                     | 
| 34 | 
            -
             | 
| 34 | 
            +
                    compose(other, Sum)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Compose two types into an Intersection type
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # @param [Type] other
         | 
| 40 | 
            +
                  #
         | 
| 41 | 
            +
                  # @return [Intersection, Intersection::Constrained]
         | 
| 42 | 
            +
                  #
         | 
| 43 | 
            +
                  # @api private
         | 
| 44 | 
            +
                  def &(other)
         | 
| 45 | 
            +
                    compose(other, Intersection)
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  # Compose two types into an Implication type
         | 
| 49 | 
            +
                  #
         | 
| 50 | 
            +
                  # @param [Type] other
         | 
| 51 | 
            +
                  #
         | 
| 52 | 
            +
                  # @return [Implication, Implication::Constrained]
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  # @api private
         | 
| 55 | 
            +
                  def >(other)
         | 
| 56 | 
            +
                    compose(other, Implication)
         | 
| 35 57 | 
             
                  end
         | 
| 36 58 |  | 
| 37 59 | 
             
                  # Turn a type into an optional type
         | 
| @@ -179,6 +201,21 @@ module Dry | |
| 179 201 | 
             
                      end
         | 
| 180 202 | 
             
                    end
         | 
| 181 203 | 
             
                  end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                  private
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  # @api private
         | 
| 208 | 
            +
                  def compose(other, composition_class)
         | 
| 209 | 
            +
                    klass =
         | 
| 210 | 
            +
                      if constrained? && other.constrained?
         | 
| 211 | 
            +
                        composition_class::Constrained
         | 
| 212 | 
            +
                      else
         | 
| 213 | 
            +
                        composition_class
         | 
| 214 | 
            +
                      end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                    klass.new(self, other)
         | 
| 217 | 
            +
                  end
         | 
| 182 218 | 
             
                end
         | 
| 219 | 
            +
                # rubocop:enable Metrics/ModuleLength
         | 
| 183 220 | 
             
              end
         | 
| 184 221 | 
             
            end
         | 
| @@ -0,0 +1,152 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "dry/core/equalizer"
         | 
| 4 | 
            +
            require "dry/types/options"
         | 
| 5 | 
            +
            require "dry/types/meta"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Dry
         | 
| 8 | 
            +
              module Types
         | 
| 9 | 
            +
                module Composition
         | 
| 10 | 
            +
                  include Type
         | 
| 11 | 
            +
                  include Builder
         | 
| 12 | 
            +
                  include Options
         | 
| 13 | 
            +
                  include Meta
         | 
| 14 | 
            +
                  include Printable
         | 
| 15 | 
            +
                  include Dry::Equalizer(:left, :right, :options, :meta, inspect: false, immutable: true)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # @return [Type]
         | 
| 18 | 
            +
                  attr_reader :left
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # @return [Type]
         | 
| 21 | 
            +
                  attr_reader :right
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  module Constrained
         | 
| 24 | 
            +
                    def rule
         | 
| 25 | 
            +
                      left.rule.public_send(self.class.operator, right.rule)
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def constrained?
         | 
| 29 | 
            +
                      true
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def self.included(base)
         | 
| 34 | 
            +
                    composition_name = Inflector.demodulize(base)
         | 
| 35 | 
            +
                    ast_type = Inflector.underscore(composition_name).to_sym
         | 
| 36 | 
            +
                    base.define_singleton_method(:ast_type) { ast_type }
         | 
| 37 | 
            +
                    base.define_singleton_method(:composition_name) { composition_name }
         | 
| 38 | 
            +
                    base.const_set("Constrained", Class.new(base) { include Constrained })
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # @param [Type] left
         | 
| 42 | 
            +
                  # @param [Type] right
         | 
| 43 | 
            +
                  # @param [Hash] options
         | 
| 44 | 
            +
                  #
         | 
| 45 | 
            +
                  # @api private
         | 
| 46 | 
            +
                  def initialize(left, right, **options)
         | 
| 47 | 
            +
                    super
         | 
| 48 | 
            +
                    @left, @right = left, right
         | 
| 49 | 
            +
                    freeze
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # @return [String]
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  # @api public
         | 
| 55 | 
            +
                  def name
         | 
| 56 | 
            +
                    [left, right].map(&:name).join(" #{self.class.operator} ")
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  # @return [false]
         | 
| 60 | 
            +
                  #
         | 
| 61 | 
            +
                  # @api public
         | 
| 62 | 
            +
                  def default?
         | 
| 63 | 
            +
                    false
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  # @return [false]
         | 
| 67 | 
            +
                  #
         | 
| 68 | 
            +
                  # @api public
         | 
| 69 | 
            +
                  def constrained?
         | 
| 70 | 
            +
                    false
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  # @return [Boolean]
         | 
| 74 | 
            +
                  #
         | 
| 75 | 
            +
                  # @api public
         | 
| 76 | 
            +
                  def optional?
         | 
| 77 | 
            +
                    false
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  # @param [Object] input
         | 
| 81 | 
            +
                  #
         | 
| 82 | 
            +
                  # @return [Object]
         | 
| 83 | 
            +
                  #
         | 
| 84 | 
            +
                  # @api private
         | 
| 85 | 
            +
                  def call_unsafe(input)
         | 
| 86 | 
            +
                    raise NotImplementedError
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  # @param [Object] input
         | 
| 90 | 
            +
                  #
         | 
| 91 | 
            +
                  # @return [Object]
         | 
| 92 | 
            +
                  #
         | 
| 93 | 
            +
                  # @api private
         | 
| 94 | 
            +
                  def call_safe(input, &block)
         | 
| 95 | 
            +
                    raise NotImplementedError
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  # @param [Object] input
         | 
| 99 | 
            +
                  #
         | 
| 100 | 
            +
                  # @api public
         | 
| 101 | 
            +
                  def try(input)
         | 
| 102 | 
            +
                    raise NotImplementedError
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  # @api private
         | 
| 106 | 
            +
                  def success(input)
         | 
| 107 | 
            +
                    result = try(input)
         | 
| 108 | 
            +
                    if result.success?
         | 
| 109 | 
            +
                      result
         | 
| 110 | 
            +
                    else
         | 
| 111 | 
            +
                      raise ArgumentError, "Invalid success value '#{input}' for #{inspect}"
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  # @api private
         | 
| 116 | 
            +
                  def failure(input, _error = nil)
         | 
| 117 | 
            +
                    result = try(input)
         | 
| 118 | 
            +
                    if result.failure?
         | 
| 119 | 
            +
                      result
         | 
| 120 | 
            +
                    else
         | 
| 121 | 
            +
                      raise ArgumentError, "Invalid failure value '#{input}' for #{inspect}"
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  # @param [Object] value
         | 
| 126 | 
            +
                  #
         | 
| 127 | 
            +
                  # @return [Boolean]
         | 
| 128 | 
            +
                  #
         | 
| 129 | 
            +
                  # @api private
         | 
| 130 | 
            +
                  def primitive?(value)
         | 
| 131 | 
            +
                    raise NotImplementedError
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  # @see Nominal#to_ast
         | 
| 135 | 
            +
                  #
         | 
| 136 | 
            +
                  # @api public
         | 
| 137 | 
            +
                  def to_ast(meta: true)
         | 
| 138 | 
            +
                    [self.class.ast_type,
         | 
| 139 | 
            +
                     [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  # Wrap the type with a proc
         | 
| 143 | 
            +
                  #
         | 
| 144 | 
            +
                  # @return [Proc]
         | 
| 145 | 
            +
                  #
         | 
| 146 | 
            +
                  # @api public
         | 
| 147 | 
            +
                  def to_proc
         | 
| 148 | 
            +
                    proc { |value| self.(value) }
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
              end
         | 
| 152 | 
            +
            end
         | 
    
        data/lib/dry/types/container.rb
    CHANGED
    
    | @@ -1,14 +1,12 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "dry/container"
         | 
| 4 | 
            -
             | 
| 5 3 | 
             
            module Dry
         | 
| 6 4 | 
             
              module Types
         | 
| 7 5 | 
             
                # Internal container for the built-in types
         | 
| 8 6 | 
             
                #
         | 
| 9 7 | 
             
                # @api private
         | 
| 10 8 | 
             
                class Container
         | 
| 11 | 
            -
                  include  | 
| 9 | 
            +
                  include Core::Container::Mixin
         | 
| 12 10 | 
             
                end
         | 
| 13 11 | 
             
              end
         | 
| 14 12 | 
             
            end
         | 
| @@ -1,6 +1,11 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "dry/monads | 
| 3 | 
            +
            require "dry/monads"
         | 
| 4 | 
            +
            require "dry/monads/version"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            if Gem::Version.new(Dry::Monads::VERSION) < Gem::Version.new("1.5.0")
         | 
| 7 | 
            +
              raise "dry-types requires dry-monads >= 1.5.0"
         | 
| 8 | 
            +
            end
         | 
| 4 9 |  | 
| 5 10 | 
             
            module Dry
         | 
| 6 11 | 
             
              module Types
         | 
| @@ -13,7 +18,7 @@ module Dry | |
| 13 18 | 
             
                  include Decorator
         | 
| 14 19 | 
             
                  include Builder
         | 
| 15 20 | 
             
                  include Printable
         | 
| 16 | 
            -
                  include ::Dry::Monads | 
| 21 | 
            +
                  include ::Dry::Monads[:maybe]
         | 
| 17 22 |  | 
| 18 23 | 
             
                  # @param [Dry::Monads::Maybe, Object] input
         | 
| 19 24 | 
             
                  #
         | 
| @@ -1,6 +1,11 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "dry/monads | 
| 3 | 
            +
            require "dry/monads"
         | 
| 4 | 
            +
            require "dry/monads/version"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            if Gem::Version.new(Dry::Monads::VERSION) < Gem::Version.new("1.5.0")
         | 
| 7 | 
            +
              raise "dry-types requires dry-monads >= 1.5.0"
         | 
| 8 | 
            +
            end
         | 
| 4 9 |  | 
| 5 10 | 
             
            module Dry
         | 
| 6 11 | 
             
              module Types
         | 
| @@ -8,7 +13,7 @@ module Dry | |
| 8 13 | 
             
                #
         | 
| 9 14 | 
             
                # @api public
         | 
| 10 15 | 
             
                class Result
         | 
| 11 | 
            -
                  include Dry::Monads | 
| 16 | 
            +
                  include ::Dry::Monads[:result]
         | 
| 12 17 |  | 
| 13 18 | 
             
                  # Turn result into a monad
         | 
| 14 19 | 
             
                  #
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Dry
         | 
| 4 | 
            +
              module Types
         | 
| 5 | 
            +
                # Implication type
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # @api public
         | 
| 8 | 
            +
                class Implication
         | 
| 9 | 
            +
                  include Composition
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def self.operator
         | 
| 12 | 
            +
                    :>
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # @param [Object] input
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # @return [Object]
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @api private
         | 
| 20 | 
            +
                  def call_unsafe(input)
         | 
| 21 | 
            +
                    if left.try(input).success?
         | 
| 22 | 
            +
                      right.call_unsafe(input)
         | 
| 23 | 
            +
                    else
         | 
| 24 | 
            +
                      input
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # @param [Object] input
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @return [Object]
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # @api private
         | 
| 33 | 
            +
                  def call_safe(input, &block)
         | 
| 34 | 
            +
                    if left.try(input).success?
         | 
| 35 | 
            +
                      right.call_safe(input, &block)
         | 
| 36 | 
            +
                    else
         | 
| 37 | 
            +
                      input
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # @param [Object] input
         | 
| 42 | 
            +
                  #
         | 
| 43 | 
            +
                  # @api public
         | 
| 44 | 
            +
                  def try(input)
         | 
| 45 | 
            +
                    if left.try(input).success?
         | 
| 46 | 
            +
                      right.try(input)
         | 
| 47 | 
            +
                    else
         | 
| 48 | 
            +
                      Result::Success.new(input)
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # @param [Object] value
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  # @return [Boolean]
         | 
| 55 | 
            +
                  #
         | 
| 56 | 
            +
                  # @api private
         | 
| 57 | 
            +
                  def primitive?(value)
         | 
| 58 | 
            +
                    if left.primitive?(value)
         | 
| 59 | 
            +
                      right.primitive?(value)
         | 
| 60 | 
            +
                    else
         | 
| 61 | 
            +
                      true
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         | 
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "dry/core/equalizer"
         | 
| 4 | 
            +
            require "dry/types/options"
         | 
| 5 | 
            +
            require "dry/types/meta"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Dry
         | 
| 8 | 
            +
              module Types
         | 
| 9 | 
            +
                # Intersection type
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # @api public
         | 
| 12 | 
            +
                class Intersection
         | 
| 13 | 
            +
                  include Composition
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def self.operator
         | 
| 16 | 
            +
                    :&
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  # @param [Object] input
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # @return [Object]
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  # @api private
         | 
| 24 | 
            +
                  def call_unsafe(input)
         | 
| 25 | 
            +
                    merge_results(left.call_unsafe(input), right.call_unsafe(input))
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # @param [Object] input
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @return [Object]
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # @api private
         | 
| 33 | 
            +
                  def call_safe(input, &block)
         | 
| 34 | 
            +
                    try_sides(input, &block).input
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # @param [Object] input
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  # @api public
         | 
| 40 | 
            +
                  def try(input)
         | 
| 41 | 
            +
                    try_sides(input) do |failure|
         | 
| 42 | 
            +
                      if block_given?
         | 
| 43 | 
            +
                        yield(failure)
         | 
| 44 | 
            +
                      else
         | 
| 45 | 
            +
                        failure
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # @param [Object] value
         | 
| 51 | 
            +
                  #
         | 
| 52 | 
            +
                  # @return [Boolean]
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  # @api private
         | 
| 55 | 
            +
                  def primitive?(value)
         | 
| 56 | 
            +
                    left.primitive?(value) && right.primitive?(value)
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  private
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  # @api private
         | 
| 62 | 
            +
                  def try_sides(input, &block)
         | 
| 63 | 
            +
                    results = []
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    [left, right].each do |side|
         | 
| 66 | 
            +
                      result = try_side(side, input, &block)
         | 
| 67 | 
            +
                      return result if result.failure?
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                      results << result
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    Result::Success.new(merge_results(*results.map(&:input)))
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  # @api private
         | 
| 76 | 
            +
                  def try_side(side, input)
         | 
| 77 | 
            +
                    failure = nil
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    result = side.try(input) do |f|
         | 
| 80 | 
            +
                      failure = f
         | 
| 81 | 
            +
                      yield(f)
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    if result.is_a?(Result)
         | 
| 85 | 
            +
                      result
         | 
| 86 | 
            +
                    elsif failure
         | 
| 87 | 
            +
                      Result::Failure.new(result, failure)
         | 
| 88 | 
            +
                    else
         | 
| 89 | 
            +
                      Result::Success.new(result)
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  # @api private
         | 
| 94 | 
            +
                  def merge_results(left_result, right_result)
         | 
| 95 | 
            +
                    case left_result
         | 
| 96 | 
            +
                    when ::Array
         | 
| 97 | 
            +
                      left_result
         | 
| 98 | 
            +
                        .zip(right_result)
         | 
| 99 | 
            +
                        .map { |lhs, rhs| merge_results(lhs, rhs) }
         | 
| 100 | 
            +
                    when ::Hash
         | 
| 101 | 
            +
                      left_result.merge(right_result)
         | 
| 102 | 
            +
                    else
         | 
| 103 | 
            +
                      left_result
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
    
        data/lib/dry/types/module.rb
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require "dry/types/builder_methods"
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Dry
         | 
| 4 6 | 
             
              module Types
         | 
| 5 7 | 
             
                # Export types registered in a container as module constants.
         | 
| @@ -44,7 +46,7 @@ module Dry | |
| 44 46 | 
             
                    elsif Undefined.equal?(default)
         | 
| 45 47 | 
             
                      default_ns = Undefined
         | 
| 46 48 | 
             
                    else
         | 
| 47 | 
            -
                      default_ns = Inflector.camelize(default).to_sym
         | 
| 49 | 
            +
                      default_ns = Types::Inflector.camelize(default).to_sym
         | 
| 48 50 | 
             
                    end
         | 
| 49 51 |  | 
| 50 52 | 
             
                    tree = registry_tree
         | 
| @@ -52,7 +54,9 @@ module Dry | |
| 52 54 | 
             
                    if namespaces.empty? && aliases.empty?
         | 
| 53 55 | 
             
                      modules = tree.select { |_, v| v.is_a?(::Hash) }.map(&:first)
         | 
| 54 56 | 
             
                    else
         | 
| 55 | 
            -
                      modules = (namespaces + aliases.keys).map { |n| | 
| 57 | 
            +
                      modules = (namespaces + aliases.keys).map { |n|
         | 
| 58 | 
            +
                        Types::Inflector.camelize(n).to_sym
         | 
| 59 | 
            +
                      }
         | 
| 56 60 | 
             
                    end
         | 
| 57 61 |  | 
| 58 62 | 
             
                    tree.each_with_object({}) do |(key, value), constants|
         | 
| @@ -73,7 +77,7 @@ module Dry | |
| 73 77 | 
             
                    @registry_tree ||= @registry.keys.each_with_object({}) { |key, tree|
         | 
| 74 78 | 
             
                      type = @registry[key]
         | 
| 75 79 | 
             
                      *modules, const_name = key.split(".").map { |part|
         | 
| 76 | 
            -
                        Inflector.camelize(part).to_sym
         | 
| 80 | 
            +
                        Types::Inflector.camelize(part).to_sym
         | 
| 77 81 | 
             
                      }
         | 
| 78 82 | 
             
                      next if modules.empty?
         | 
| 79 83 |  | 
| @@ -15,27 +15,14 @@ module Dry | |
| 15 15 | 
             
                  KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
         | 
| 16 16 | 
             
                  private_constant(:KERNEL_RESPOND_TO)
         | 
| 17 17 |  | 
| 18 | 
            -
                   | 
| 19 | 
            -
             | 
| 20 | 
            -
                     | 
| 21 | 
            -
             | 
| 22 | 
            -
                    end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                    # @api private
         | 
| 25 | 
            -
                    def key?(name)
         | 
| 26 | 
            -
                      KERNEL_RESPOND_TO.bind_call(@predicates, name)
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
                  else
         | 
| 29 | 
            -
                    # @api private
         | 
| 30 | 
            -
                    def initialize(predicates = Logic::Predicates)
         | 
| 31 | 
            -
                      @predicates = predicates
         | 
| 32 | 
            -
                      @has_predicate = KERNEL_RESPOND_TO.bind(@predicates)
         | 
| 33 | 
            -
                    end
         | 
| 18 | 
            +
                  # @api private
         | 
| 19 | 
            +
                  def initialize(predicates = Logic::Predicates)
         | 
| 20 | 
            +
                    @predicates = predicates
         | 
| 21 | 
            +
                  end
         | 
| 34 22 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                    end
         | 
| 23 | 
            +
                  # @api private
         | 
| 24 | 
            +
                  def key?(name)
         | 
| 25 | 
            +
                    KERNEL_RESPOND_TO.bind_call(@predicates, name)
         | 
| 39 26 | 
             
                  end
         | 
| 40 27 |  | 
| 41 28 | 
             
                  # @api private
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Dry
         | 
| 4 | 
            +
              module Types
         | 
| 5 | 
            +
                # @api private
         | 
| 6 | 
            +
                class Printer
         | 
| 7 | 
            +
                  # @api private
         | 
| 8 | 
            +
                  class Composition
         | 
| 9 | 
            +
                    def initialize(printer, composition_class)
         | 
| 10 | 
            +
                      @printer = printer
         | 
| 11 | 
            +
                      @composition_class = composition_class
         | 
| 12 | 
            +
                      freeze
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def visit(composition)
         | 
| 16 | 
            +
                      visit_constructors(composition) do |constructors|
         | 
| 17 | 
            +
                        @printer.visit_options(composition.options, composition.meta) do |opts|
         | 
| 18 | 
            +
                          yield "#{@composition_class.composition_name}<#{constructors}#{opts}>"
         | 
| 19 | 
            +
                        end
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    private
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def visit_constructors(composition)
         | 
| 26 | 
            +
                      visit_constructor(composition.left) do |left|
         | 
| 27 | 
            +
                        visit_constructor(composition.right) do |right|
         | 
| 28 | 
            +
                          yield "#{left} #{@composition_class.operator} #{right}"
         | 
| 29 | 
            +
                        end
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def visit_constructor(type, &block)
         | 
| 34 | 
            +
                      case type
         | 
| 35 | 
            +
                      when @composition_class
         | 
| 36 | 
            +
                        visit_constructors(type, &block)
         | 
| 37 | 
            +
                      else
         | 
| 38 | 
            +
                        @printer.visit(type, &block)
         | 
| 39 | 
            +
                      end
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
    
        data/lib/dry/types/printer.rb
    CHANGED
    
    | @@ -1,17 +1,21 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require "dry/types/printer/composition"
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Dry
         | 
| 4 6 | 
             
              # rubocop:disable Metrics/AbcSize
         | 
| 5 7 | 
             
              # rubocop:disable Metrics/PerceivedComplexity
         | 
| 6 8 | 
             
              module Types
         | 
| 7 9 | 
             
                # @api private
         | 
| 8 10 | 
             
                class Printer
         | 
| 9 | 
            -
                  MAPPING = { | 
| 11 | 
            +
                  MAPPING = {
         | 
| 10 12 | 
             
                    Nominal => :visit_nominal,
         | 
| 11 13 | 
             
                    Constructor => :visit_constructor,
         | 
| 12 | 
            -
                     | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 14 | 
            +
                    [
         | 
| 15 | 
            +
                      Constrained,
         | 
| 16 | 
            +
                      Constrained::Coercible
         | 
| 17 | 
            +
                    ] => :visit_constrained,
         | 
| 18 | 
            +
                    Types::Hash => :visit_hash,
         | 
| 15 19 | 
             
                    Schema => :visit_schema,
         | 
| 16 20 | 
             
                    Schema::Key => :visit_key,
         | 
| 17 21 | 
             
                    Map => :visit_map,
         | 
| @@ -19,12 +23,22 @@ module Dry | |
| 19 23 | 
             
                    Array::Member => :visit_array_member,
         | 
| 20 24 | 
             
                    Lax => :visit_lax,
         | 
| 21 25 | 
             
                    Enum => :visit_enum,
         | 
| 22 | 
            -
                    Default => :visit_default,
         | 
| 23 | 
            -
                     | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            +
                    [Default, Default::Callable] => :visit_default,
         | 
| 27 | 
            +
                    [
         | 
| 28 | 
            +
                      Sum,
         | 
| 29 | 
            +
                      Sum::Constrained,
         | 
| 30 | 
            +
                      Intersection,
         | 
| 31 | 
            +
                      Intersection::Constrained,
         | 
| 32 | 
            +
                      Implication,
         | 
| 33 | 
            +
                      Implication::Constrained
         | 
| 34 | 
            +
                    ] => :visit_composition,
         | 
| 26 35 | 
             
                    Any.class => :visit_any
         | 
| 27 | 
            -
                  }
         | 
| 36 | 
            +
                  }.flat_map { |k, v| Array(k).map { |kk| [kk, v] } }.to_h
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def initialize
         | 
| 39 | 
            +
                    @composition_printers = {}
         | 
| 40 | 
            +
                    freeze
         | 
| 41 | 
            +
                  end
         | 
| 28 42 |  | 
| 29 43 | 
             
                  def call(type)
         | 
| 30 44 | 
             
                    output = "".dup
         | 
| @@ -87,106 +101,10 @@ module Dry | |
| 87 101 | 
             
                    end
         | 
| 88 102 | 
             
                  end
         | 
| 89 103 |  | 
| 90 | 
            -
                  def  | 
| 91 | 
            -
                     | 
| 92 | 
            -
                     | 
| 93 | 
            -
                     | 
| 94 | 
            -
                    type_fn_str = ""
         | 
| 95 | 
            -
                    strict_str = ""
         | 
| 96 | 
            -
             | 
| 97 | 
            -
                    strict_str = "strict " if options.delete(:strict)
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                    if (key_fn = options.delete(:key_transform_fn))
         | 
| 100 | 
            -
                      visit_callable(key_fn) do |fn|
         | 
| 101 | 
            -
                        key_fn_str = "key_fn=#{fn} "
         | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                    if (type_fn = options.delete(:type_transform_fn))
         | 
| 106 | 
            -
                      visit_callable(type_fn) do |fn|
         | 
| 107 | 
            -
                        type_fn_str = "type_fn=#{fn} "
         | 
| 108 | 
            -
                      end
         | 
| 109 | 
            -
                    end
         | 
| 110 | 
            -
             | 
| 111 | 
            -
                    keys = options.delete(:keys)
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                    visit_options(options, schema.meta) do |opts|
         | 
| 114 | 
            -
                      opts = "#{opts[1..]} " unless opts.empty?
         | 
| 115 | 
            -
                      schema_parameters = "#{key_fn_str}#{type_fn_str}#{strict_str}#{opts}"
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                      header = "Schema<#{schema_parameters}keys={"
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                      if size.zero?
         | 
| 120 | 
            -
                        yield "#{header}}>"
         | 
| 121 | 
            -
                      else
         | 
| 122 | 
            -
                        yield header.dup << keys.map { |key|
         | 
| 123 | 
            -
                          visit(key) { |type| type }
         | 
| 124 | 
            -
                        }.join(" ") << "}>"
         | 
| 125 | 
            -
                      end
         | 
| 126 | 
            -
                    end
         | 
| 127 | 
            -
                  end
         | 
| 128 | 
            -
             | 
| 129 | 
            -
                  def visit_map(map)
         | 
| 130 | 
            -
                    visit(map.key_type) do |key|
         | 
| 131 | 
            -
                      visit(map.value_type) do |value|
         | 
| 132 | 
            -
                        options = map.options.dup
         | 
| 133 | 
            -
                        options.delete(:key_type)
         | 
| 134 | 
            -
                        options.delete(:value_type)
         | 
| 135 | 
            -
             | 
| 136 | 
            -
                        visit_options(options) do |_opts|
         | 
| 137 | 
            -
                          yield "Map<#{key} => #{value}>"
         | 
| 138 | 
            -
                        end
         | 
| 139 | 
            -
                      end
         | 
| 140 | 
            -
                    end
         | 
| 141 | 
            -
                  end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                  def visit_key(key)
         | 
| 144 | 
            -
                    visit(key.type) do |type|
         | 
| 145 | 
            -
                      if key.required?
         | 
| 146 | 
            -
                        yield "#{key.name}: #{type}"
         | 
| 147 | 
            -
                      else
         | 
| 148 | 
            -
                        yield "#{key.name}?: #{type}"
         | 
| 149 | 
            -
                      end
         | 
| 150 | 
            -
                    end
         | 
| 151 | 
            -
                  end
         | 
| 152 | 
            -
             | 
| 153 | 
            -
                  def visit_sum(sum)
         | 
| 154 | 
            -
                    visit_sum_constructors(sum) do |constructors|
         | 
| 155 | 
            -
                      visit_options(sum.options, sum.meta) do |opts|
         | 
| 156 | 
            -
                        yield "Sum<#{constructors}#{opts}>"
         | 
| 157 | 
            -
                      end
         | 
| 158 | 
            -
                    end
         | 
| 159 | 
            -
                  end
         | 
| 160 | 
            -
             | 
| 161 | 
            -
                  def visit_sum_constructors(sum)
         | 
| 162 | 
            -
                    case sum.left
         | 
| 163 | 
            -
                    when Sum
         | 
| 164 | 
            -
                      visit_sum_constructors(sum.left) do |left|
         | 
| 165 | 
            -
                        case sum.right
         | 
| 166 | 
            -
                        when Sum
         | 
| 167 | 
            -
                          visit_sum_constructors(sum.right) do |right|
         | 
| 168 | 
            -
                            yield "#{left} | #{right}"
         | 
| 169 | 
            -
                          end
         | 
| 170 | 
            -
                        else
         | 
| 171 | 
            -
                          visit(sum.right) do |right|
         | 
| 172 | 
            -
                            yield "#{left} | #{right}"
         | 
| 173 | 
            -
                          end
         | 
| 174 | 
            -
                        end
         | 
| 175 | 
            -
                      end
         | 
| 176 | 
            -
                    else
         | 
| 177 | 
            -
                      visit(sum.left) do |left|
         | 
| 178 | 
            -
                        case sum.right
         | 
| 179 | 
            -
                        when Sum
         | 
| 180 | 
            -
                          visit_sum_constructors(sum.right) do |right|
         | 
| 181 | 
            -
                            yield "#{left} | #{right}"
         | 
| 182 | 
            -
                          end
         | 
| 183 | 
            -
                        else
         | 
| 184 | 
            -
                          visit(sum.right) do |right|
         | 
| 185 | 
            -
                            yield "#{left} | #{right}"
         | 
| 186 | 
            -
                          end
         | 
| 187 | 
            -
                        end
         | 
| 188 | 
            -
                      end
         | 
| 189 | 
            -
                    end
         | 
| 104 | 
            +
                  def visit_composition(composition, &block)
         | 
| 105 | 
            +
                    klass = composition.class
         | 
| 106 | 
            +
                    @composition_printers[klass] = Composition.new(self, klass)
         | 
| 107 | 
            +
                    @composition_printers[klass].visit(composition, &block)
         | 
| 190 108 | 
             
                  end
         | 
| 191 109 |  | 
| 192 110 | 
             
                  def visit_enum(enum)
         | 
| @@ -234,25 +152,6 @@ module Dry | |
| 234 152 | 
             
                    end
         | 
| 235 153 | 
             
                  end
         | 
| 236 154 |  | 
| 237 | 
            -
                  def visit_hash(hash)
         | 
| 238 | 
            -
                    options = hash.options.dup
         | 
| 239 | 
            -
                    type_fn_str = ""
         | 
| 240 | 
            -
             | 
| 241 | 
            -
                    if (type_fn = options.delete(:type_transform_fn))
         | 
| 242 | 
            -
                      visit_callable(type_fn) do |fn|
         | 
| 243 | 
            -
                        type_fn_str = "type_fn=#{fn}"
         | 
| 244 | 
            -
                      end
         | 
| 245 | 
            -
                    end
         | 
| 246 | 
            -
             | 
| 247 | 
            -
                    visit_options(options, hash.meta) do |opts|
         | 
| 248 | 
            -
                      if opts.empty? && type_fn_str.empty?
         | 
| 249 | 
            -
                        yield "Hash"
         | 
| 250 | 
            -
                      else
         | 
| 251 | 
            -
                        yield "Hash<#{type_fn_str}#{opts}>"
         | 
| 252 | 
            -
                      end
         | 
| 253 | 
            -
                    end
         | 
| 254 | 
            -
                  end
         | 
| 255 | 
            -
             | 
| 256 155 | 
             
                  def visit_callable(callable)
         | 
| 257 156 | 
             
                    fn = callable.is_a?(String) ? FnContainer[callable] : callable
         | 
| 258 157 |  | 
| @@ -288,6 +187,88 @@ module Dry | |
| 288 187 | 
             
                    end
         | 
| 289 188 | 
             
                  end
         | 
| 290 189 |  | 
| 190 | 
            +
                  def visit_schema(schema)
         | 
| 191 | 
            +
                    options = schema.options.dup
         | 
| 192 | 
            +
                    size = schema.count
         | 
| 193 | 
            +
                    key_fn_str = ""
         | 
| 194 | 
            +
                    type_fn_str = ""
         | 
| 195 | 
            +
                    strict_str = ""
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                    strict_str = "strict " if options.delete(:strict)
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                    if (key_fn = options.delete(:key_transform_fn))
         | 
| 200 | 
            +
                      visit_callable(key_fn) do |fn|
         | 
| 201 | 
            +
                        key_fn_str = "key_fn=#{fn} "
         | 
| 202 | 
            +
                      end
         | 
| 203 | 
            +
                    end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                    if (type_fn = options.delete(:type_transform_fn))
         | 
| 206 | 
            +
                      visit_callable(type_fn) do |fn|
         | 
| 207 | 
            +
                        type_fn_str = "type_fn=#{fn} "
         | 
| 208 | 
            +
                      end
         | 
| 209 | 
            +
                    end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                    keys = options.delete(:keys)
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                    visit_options(options, schema.meta) do |opts|
         | 
| 214 | 
            +
                      opts = "#{opts[1..]} " unless opts.empty?
         | 
| 215 | 
            +
                      schema_parameters = "#{key_fn_str}#{type_fn_str}#{strict_str}#{opts}"
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                      header = "Schema<#{schema_parameters}keys={"
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                      if size.zero?
         | 
| 220 | 
            +
                        yield "#{header}}>"
         | 
| 221 | 
            +
                      else
         | 
| 222 | 
            +
                        yield header.dup << keys.map { |key|
         | 
| 223 | 
            +
                          visit(key) { |type| type }
         | 
| 224 | 
            +
                        }.join(" ") << "}>"
         | 
| 225 | 
            +
                      end
         | 
| 226 | 
            +
                    end
         | 
| 227 | 
            +
                  end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                  def visit_map(map)
         | 
| 230 | 
            +
                    visit(map.key_type) do |key|
         | 
| 231 | 
            +
                      visit(map.value_type) do |value|
         | 
| 232 | 
            +
                        options = map.options.dup
         | 
| 233 | 
            +
                        options.delete(:key_type)
         | 
| 234 | 
            +
                        options.delete(:value_type)
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                        visit_options(options) do |_opts|
         | 
| 237 | 
            +
                          yield "Map<#{key} => #{value}>"
         | 
| 238 | 
            +
                        end
         | 
| 239 | 
            +
                      end
         | 
| 240 | 
            +
                    end
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                  def visit_key(key)
         | 
| 244 | 
            +
                    visit(key.type) do |type|
         | 
| 245 | 
            +
                      if key.required?
         | 
| 246 | 
            +
                        yield "#{key.name}: #{type}"
         | 
| 247 | 
            +
                      else
         | 
| 248 | 
            +
                        yield "#{key.name}?: #{type}"
         | 
| 249 | 
            +
                      end
         | 
| 250 | 
            +
                    end
         | 
| 251 | 
            +
                  end
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                  def visit_hash(hash)
         | 
| 254 | 
            +
                    options = hash.options.dup
         | 
| 255 | 
            +
                    type_fn_str = ""
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                    if (type_fn = options.delete(:type_transform_fn))
         | 
| 258 | 
            +
                      visit_callable(type_fn) do |fn|
         | 
| 259 | 
            +
                        type_fn_str = "type_fn=#{fn}"
         | 
| 260 | 
            +
                      end
         | 
| 261 | 
            +
                    end
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                    visit_options(options, hash.meta) do |opts|
         | 
| 264 | 
            +
                      if opts.empty? && type_fn_str.empty?
         | 
| 265 | 
            +
                        yield "Hash"
         | 
| 266 | 
            +
                      else
         | 
| 267 | 
            +
                        yield "Hash<#{type_fn_str}#{opts}>"
         | 
| 268 | 
            +
                      end
         | 
| 269 | 
            +
                    end
         | 
| 270 | 
            +
                  end
         | 
| 271 | 
            +
             | 
| 291 272 | 
             
                  def visit_options(options, meta = EMPTY_HASH) # rubocop:disable Metrics/PerceivedComplexity
         | 
| 292 273 | 
             
                    if options.empty? && meta.empty?
         | 
| 293 274 | 
             
                      yield ""
         | 
| @@ -312,7 +293,7 @@ module Dry | |
| 312 293 | 
             
                  end
         | 
| 313 294 | 
             
                end
         | 
| 314 295 |  | 
| 315 | 
            -
                PRINTER = Printer.new | 
| 296 | 
            +
                PRINTER = Printer.new
         | 
| 316 297 | 
             
              end
         | 
| 317 298 | 
             
              # rubocop:enable Metrics/AbcSize
         | 
| 318 299 | 
             
              # rubocop:enable Metrics/PerceivedComplexity
         | 
    
        data/lib/dry/types/sum.rb
    CHANGED
    
    | @@ -6,62 +6,10 @@ module Dry | |
| 6 6 | 
             
                #
         | 
| 7 7 | 
             
                # @api public
         | 
| 8 8 | 
             
                class Sum
         | 
| 9 | 
            -
                  include  | 
| 10 | 
            -
                  include Builder
         | 
| 11 | 
            -
                  include Options
         | 
| 12 | 
            -
                  include Meta
         | 
| 13 | 
            -
                  include Printable
         | 
| 14 | 
            -
                  include Dry::Equalizer(:left, :right, :options, :meta, inspect: false, immutable: true)
         | 
| 9 | 
            +
                  include Composition
         | 
| 15 10 |  | 
| 16 | 
            -
                   | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                  # @return [Type]
         | 
| 20 | 
            -
                  attr_reader :right
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  # @api private
         | 
| 23 | 
            -
                  class Constrained < Sum
         | 
| 24 | 
            -
                    # @return [Dry::Logic::Operations::Or]
         | 
| 25 | 
            -
                    def rule
         | 
| 26 | 
            -
                      left.rule | right.rule
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                    # @return [true]
         | 
| 30 | 
            -
                    def constrained?
         | 
| 31 | 
            -
                      true
         | 
| 32 | 
            -
                    end
         | 
| 33 | 
            -
                  end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                  # @param [Type] left
         | 
| 36 | 
            -
                  # @param [Type] right
         | 
| 37 | 
            -
                  # @param [Hash] options
         | 
| 38 | 
            -
                  #
         | 
| 39 | 
            -
                  # @api private
         | 
| 40 | 
            -
                  def initialize(left, right, **options)
         | 
| 41 | 
            -
                    super
         | 
| 42 | 
            -
                    @left, @right = left, right
         | 
| 43 | 
            -
                    freeze
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  # @return [String]
         | 
| 47 | 
            -
                  #
         | 
| 48 | 
            -
                  # @api public
         | 
| 49 | 
            -
                  def name
         | 
| 50 | 
            -
                    [left, right].map(&:name).join(" | ")
         | 
| 51 | 
            -
                  end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  # @return [false]
         | 
| 54 | 
            -
                  #
         | 
| 55 | 
            -
                  # @api public
         | 
| 56 | 
            -
                  def default?
         | 
| 57 | 
            -
                    false
         | 
| 58 | 
            -
                  end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                  # @return [false]
         | 
| 61 | 
            -
                  #
         | 
| 62 | 
            -
                  # @api public
         | 
| 63 | 
            -
                  def constrained?
         | 
| 64 | 
            -
                    false
         | 
| 11 | 
            +
                  def self.operator
         | 
| 12 | 
            +
                    :|
         | 
| 65 13 | 
             
                  end
         | 
| 66 14 |  | 
| 67 15 | 
             
                  # @return [Boolean]
         | 
| @@ -104,26 +52,6 @@ module Dry | |
| 104 52 | 
             
                    end
         | 
| 105 53 | 
             
                  end
         | 
| 106 54 |  | 
| 107 | 
            -
                  # @api private
         | 
| 108 | 
            -
                  def success(input)
         | 
| 109 | 
            -
                    if left.valid?(input)
         | 
| 110 | 
            -
                      left.success(input)
         | 
| 111 | 
            -
                    elsif right.valid?(input)
         | 
| 112 | 
            -
                      right.success(input)
         | 
| 113 | 
            -
                    else
         | 
| 114 | 
            -
                      raise ArgumentError, "Invalid success value '#{input}' for #{inspect}"
         | 
| 115 | 
            -
                    end
         | 
| 116 | 
            -
                  end
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                  # @api private
         | 
| 119 | 
            -
                  def failure(input, _error = nil)
         | 
| 120 | 
            -
                    if left.valid?(input)
         | 
| 121 | 
            -
                      right.failure(input, right.try(input).error)
         | 
| 122 | 
            -
                    else
         | 
| 123 | 
            -
                      left.failure(input, left.try(input).error)
         | 
| 124 | 
            -
                    end
         | 
| 125 | 
            -
                  end
         | 
| 126 | 
            -
             | 
| 127 55 | 
             
                  # @param [Object] value
         | 
| 128 56 | 
             
                  #
         | 
| 129 57 | 
             
                  # @return [Boolean]
         | 
| @@ -149,13 +77,6 @@ module Dry | |
| 149 77 | 
             
                    end
         | 
| 150 78 | 
             
                  end
         | 
| 151 79 |  | 
| 152 | 
            -
                  # @see Nominal#to_ast
         | 
| 153 | 
            -
                  #
         | 
| 154 | 
            -
                  # @api public
         | 
| 155 | 
            -
                  def to_ast(meta: true)
         | 
| 156 | 
            -
                    [:sum, [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
         | 
| 157 | 
            -
                  end
         | 
| 158 | 
            -
             | 
| 159 80 | 
             
                  # @param [Hash] options
         | 
| 160 81 | 
             
                  #
         | 
| 161 82 | 
             
                  # @return [Constrained,Sum]
         | 
| @@ -170,15 +91,6 @@ module Dry | |
| 170 91 | 
             
                      super
         | 
| 171 92 | 
             
                    end
         | 
| 172 93 | 
             
                  end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                  # Wrap the type with a proc
         | 
| 175 | 
            -
                  #
         | 
| 176 | 
            -
                  # @return [Proc]
         | 
| 177 | 
            -
                  #
         | 
| 178 | 
            -
                  # @api public
         | 
| 179 | 
            -
                  def to_proc
         | 
| 180 | 
            -
                    proc { |value| self.(value) }
         | 
| 181 | 
            -
                  end
         | 
| 182 94 | 
             
                end
         | 
| 183 95 | 
             
              end
         | 
| 184 96 | 
             
            end
         | 
    
        data/lib/dry/types/version.rb
    CHANGED
    
    
    
        data/lib/dry/types.rb
    CHANGED
    
    | @@ -8,13 +8,16 @@ require "zeitwerk" | |
| 8 8 | 
             
            require "concurrent/map"
         | 
| 9 9 |  | 
| 10 10 | 
             
            require "dry/core"
         | 
| 11 | 
            -
            require "dry/container"
         | 
| 12 11 | 
             
            require "dry/logic"
         | 
| 13 12 |  | 
| 14 13 | 
             
            require "dry/types/constraints"
         | 
| 15 14 | 
             
            require "dry/types/errors"
         | 
| 16 15 | 
             
            require "dry/types/version"
         | 
| 17 16 |  | 
| 17 | 
            +
            # This must be required explicitly as it may conflict with dry-inflector
         | 
| 18 | 
            +
            require "dry/types/inflector"
         | 
| 19 | 
            +
            require "dry/types/module"
         | 
| 20 | 
            +
             | 
| 18 21 | 
             
            module Dry
         | 
| 19 22 | 
             
              # Main library namespace
         | 
| 20 23 | 
             
              #
         | 
| @@ -37,6 +40,7 @@ module Dry | |
| 37 40 | 
             
                    loader.ignore(
         | 
| 38 41 | 
             
                      "#{root}/dry-types.rb",
         | 
| 39 42 | 
             
                      "#{root}/dry/types/extensions",
         | 
| 43 | 
            +
                      "#{root}/dry/types/printer",
         | 
| 40 44 | 
             
                      "#{root}/dry/types/spec/types.rb",
         | 
| 41 45 | 
             
                      "#{root}/dry/types/{#{%w[
         | 
| 42 46 | 
             
                        compat
         | 
| @@ -44,6 +48,8 @@ module Dry | |
| 44 48 | 
             
                        core
         | 
| 45 49 | 
             
                        errors
         | 
| 46 50 | 
             
                        extensions
         | 
| 51 | 
            +
                        inflector
         | 
| 52 | 
            +
                        module
         | 
| 47 53 | 
             
                        json
         | 
| 48 54 | 
             
                        params
         | 
| 49 55 | 
             
                        printer
         | 
| @@ -141,7 +147,7 @@ module Dry | |
| 141 147 | 
             
                #
         | 
| 142 148 | 
             
                # @return [String]
         | 
| 143 149 | 
             
                def self.identifier(klass)
         | 
| 144 | 
            -
                  Inflector.underscore(klass).tr("/", ".")
         | 
| 150 | 
            +
                  Types::Inflector.underscore(klass).tr("/", ".")
         | 
| 145 151 | 
             
                end
         | 
| 146 152 |  | 
| 147 153 | 
             
                # Cached type map
         | 
| @@ -155,7 +161,7 @@ module Dry | |
| 155 161 |  | 
| 156 162 | 
             
                # @api private
         | 
| 157 163 | 
             
                def self.const_missing(const)
         | 
| 158 | 
            -
                  underscored = Inflector.underscore(const)
         | 
| 164 | 
            +
                  underscored = Types::Inflector.underscore(const)
         | 
| 159 165 |  | 
| 160 166 | 
             
                  if container.keys.any? { |key| key.split(".")[0] == underscored }
         | 
| 161 167 | 
             
                    raise ::NameError,
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: dry-types
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.7.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Piotr Solnica
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-11-04 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: concurrent-ruby
         | 
| @@ -24,80 +24,66 @@ dependencies: | |
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '1.0'
         | 
| 27 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            -
              name: dry-container
         | 
| 29 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            -
                requirements:
         | 
| 31 | 
            -
                - - "~>"
         | 
| 32 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: '0.3'
         | 
| 34 | 
            -
              type: :runtime
         | 
| 35 | 
            -
              prerelease: false
         | 
| 36 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            -
                requirements:
         | 
| 38 | 
            -
                - - "~>"
         | 
| 39 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: '0.3'
         | 
| 41 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 28 | 
             
              name: dry-core
         | 
| 43 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 30 | 
             
                requirements:
         | 
| 45 31 | 
             
                - - "~>"
         | 
| 46 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: '0 | 
| 48 | 
            -
                - - " | 
| 33 | 
            +
                    version: '1.0'
         | 
| 34 | 
            +
                - - "<"
         | 
| 49 35 | 
             
                  - !ruby/object:Gem::Version
         | 
| 50 | 
            -
                    version: ' | 
| 36 | 
            +
                    version: '2'
         | 
| 51 37 | 
             
              type: :runtime
         | 
| 52 38 | 
             
              prerelease: false
         | 
| 53 39 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 54 40 | 
             
                requirements:
         | 
| 55 41 | 
             
                - - "~>"
         | 
| 56 42 | 
             
                  - !ruby/object:Gem::Version
         | 
| 57 | 
            -
                    version: '0 | 
| 58 | 
            -
                - - " | 
| 43 | 
            +
                    version: '1.0'
         | 
| 44 | 
            +
                - - "<"
         | 
| 59 45 | 
             
                  - !ruby/object:Gem::Version
         | 
| 60 | 
            -
                    version: ' | 
| 46 | 
            +
                    version: '2'
         | 
| 61 47 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 62 48 | 
             
              name: dry-inflector
         | 
| 63 49 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 64 50 | 
             
                requirements:
         | 
| 65 51 | 
             
                - - "~>"
         | 
| 66 52 | 
             
                  - !ruby/object:Gem::Version
         | 
| 67 | 
            -
                    version: '0 | 
| 68 | 
            -
                - - " | 
| 53 | 
            +
                    version: '1.0'
         | 
| 54 | 
            +
                - - "<"
         | 
| 69 55 | 
             
                  - !ruby/object:Gem::Version
         | 
| 70 | 
            -
                    version:  | 
| 56 | 
            +
                    version: '2'
         | 
| 71 57 | 
             
              type: :runtime
         | 
| 72 58 | 
             
              prerelease: false
         | 
| 73 59 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 74 60 | 
             
                requirements:
         | 
| 75 61 | 
             
                - - "~>"
         | 
| 76 62 | 
             
                  - !ruby/object:Gem::Version
         | 
| 77 | 
            -
                    version: '0 | 
| 78 | 
            -
                - - " | 
| 63 | 
            +
                    version: '1.0'
         | 
| 64 | 
            +
                - - "<"
         | 
| 79 65 | 
             
                  - !ruby/object:Gem::Version
         | 
| 80 | 
            -
                    version:  | 
| 66 | 
            +
                    version: '2'
         | 
| 81 67 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 82 68 | 
             
              name: dry-logic
         | 
| 83 69 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 84 70 | 
             
                requirements:
         | 
| 85 | 
            -
                - - "~>"
         | 
| 86 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 87 | 
            -
                    version: '1.3'
         | 
| 88 71 | 
             
                - - ">="
         | 
| 89 72 | 
             
                  - !ruby/object:Gem::Version
         | 
| 90 | 
            -
                    version: '1. | 
| 73 | 
            +
                    version: '1.4'
         | 
| 74 | 
            +
                - - "<"
         | 
| 75 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 76 | 
            +
                    version: '2'
         | 
| 91 77 | 
             
              type: :runtime
         | 
| 92 78 | 
             
              prerelease: false
         | 
| 93 79 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 94 80 | 
             
                requirements:
         | 
| 95 | 
            -
                - - "~>"
         | 
| 96 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 97 | 
            -
                    version: '1.3'
         | 
| 98 81 | 
             
                - - ">="
         | 
| 99 82 | 
             
                  - !ruby/object:Gem::Version
         | 
| 100 | 
            -
                    version: '1. | 
| 83 | 
            +
                    version: '1.4'
         | 
| 84 | 
            +
                - - "<"
         | 
| 85 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 86 | 
            +
                    version: '2'
         | 
| 101 87 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 102 88 | 
             
              name: zeitwerk
         | 
| 103 89 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -126,20 +112,6 @@ dependencies: | |
| 126 112 | 
             
                - - ">="
         | 
| 127 113 | 
             
                  - !ruby/object:Gem::Version
         | 
| 128 114 | 
             
                    version: '0'
         | 
| 129 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 130 | 
            -
              name: dry-monads
         | 
| 131 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 132 | 
            -
                requirements:
         | 
| 133 | 
            -
                - - "~>"
         | 
| 134 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 135 | 
            -
                    version: '1.0'
         | 
| 136 | 
            -
              type: :development
         | 
| 137 | 
            -
              prerelease: false
         | 
| 138 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 139 | 
            -
                requirements:
         | 
| 140 | 
            -
                - - "~>"
         | 
| 141 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 142 | 
            -
                    version: '1.0'
         | 
| 143 115 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 144 116 | 
             
              name: rake
         | 
| 145 117 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -207,6 +179,7 @@ files: | |
| 207 179 | 
             
            - lib/dry/types/coercions/params.rb
         | 
| 208 180 | 
             
            - lib/dry/types/compat.rb
         | 
| 209 181 | 
             
            - lib/dry/types/compiler.rb
         | 
| 182 | 
            +
            - lib/dry/types/composition.rb
         | 
| 210 183 | 
             
            - lib/dry/types/constrained.rb
         | 
| 211 184 | 
             
            - lib/dry/types/constrained/coercible.rb
         | 
| 212 185 | 
             
            - lib/dry/types/constraints.rb
         | 
| @@ -225,7 +198,9 @@ files: | |
| 225 198 | 
             
            - lib/dry/types/fn_container.rb
         | 
| 226 199 | 
             
            - lib/dry/types/hash.rb
         | 
| 227 200 | 
             
            - lib/dry/types/hash/constructor.rb
         | 
| 201 | 
            +
            - lib/dry/types/implication.rb
         | 
| 228 202 | 
             
            - lib/dry/types/inflector.rb
         | 
| 203 | 
            +
            - lib/dry/types/intersection.rb
         | 
| 229 204 | 
             
            - lib/dry/types/json.rb
         | 
| 230 205 | 
             
            - lib/dry/types/lax.rb
         | 
| 231 206 | 
             
            - lib/dry/types/map.rb
         | 
| @@ -239,6 +214,7 @@ files: | |
| 239 214 | 
             
            - lib/dry/types/primitive_inferrer.rb
         | 
| 240 215 | 
             
            - lib/dry/types/printable.rb
         | 
| 241 216 | 
             
            - lib/dry/types/printer.rb
         | 
| 217 | 
            +
            - lib/dry/types/printer/composition.rb
         | 
| 242 218 | 
             
            - lib/dry/types/result.rb
         | 
| 243 219 | 
             
            - lib/dry/types/schema.rb
         | 
| 244 220 | 
             
            - lib/dry/types/schema/key.rb
         |