dry-types 1.5.1 → 1.7.2
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 +50 -0
- data/LICENSE +1 -1
- data/README.md +7 -13
- data/dry-types.gemspec +19 -18
- data/lib/dry/types/array/constructor.rb +0 -2
- data/lib/dry/types/array/member.rb +1 -3
- data/lib/dry/types/array.rb +0 -3
- data/lib/dry/types/builder.rb +43 -14
- data/lib/dry/types/builder_methods.rb +1 -1
- data/lib/dry/types/coercions/params.rb +4 -3
- data/lib/dry/types/compat.rb +1 -0
- data/lib/dry/types/compiler.rb +1 -3
- data/lib/dry/types/composition.rb +152 -0
- data/lib/dry/types/constrained.rb +0 -5
- data/lib/dry/types/constraints.rb +3 -7
- data/lib/dry/types/constructor/function.rb +8 -9
- data/lib/dry/types/constructor.rb +4 -10
- data/lib/dry/types/container.rb +1 -3
- data/lib/dry/types/core.rb +2 -3
- data/lib/dry/types/decorator.rb +0 -2
- data/lib/dry/types/default.rb +3 -6
- data/lib/dry/types/enum.rb +0 -3
- data/lib/dry/types/errors.rb +13 -1
- data/lib/dry/types/extensions/maybe.rb +8 -5
- data/lib/dry/types/extensions/monads.rb +7 -2
- data/lib/dry/types/fn_container.rb +0 -2
- data/lib/dry/types/hash/constructor.rb +2 -4
- data/lib/dry/types/hash.rb +1 -6
- data/lib/dry/types/implication.rb +66 -0
- data/lib/dry/types/intersection.rb +108 -0
- data/lib/dry/types/lax.rb +1 -4
- data/lib/dry/types/map.rb +9 -3
- data/lib/dry/types/module.rb +18 -9
- data/lib/dry/types/nominal.rb +2 -13
- data/lib/dry/types/predicate_inferrer.rb +8 -9
- data/lib/dry/types/predicate_registry.rb +7 -7
- data/lib/dry/types/primitive_inferrer.rb +0 -2
- data/lib/dry/types/printer/composition.rb +44 -0
- data/lib/dry/types/printer.rb +116 -131
- data/lib/dry/types/result.rb +0 -2
- data/lib/dry/types/schema/key.rb +1 -4
- data/lib/dry/types/schema.rb +6 -4
- data/lib/dry/types/sum.rb +3 -95
- data/lib/dry/types/type.rb +1 -3
- data/lib/dry/types/version.rb +1 -1
- data/lib/dry/types.rb +49 -22
- metadata +32 -46
data/lib/dry/types/decorator.rb
CHANGED
data/lib/dry/types/default.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/core/equalizer"
|
4
|
-
require "dry/types/decorator"
|
5
|
-
|
6
3
|
module Dry
|
7
4
|
module Types
|
8
5
|
# Default types are useful when a missing value should be replaced by a default one
|
@@ -53,7 +50,7 @@ module Dry
|
|
53
50
|
# @param [Object] value
|
54
51
|
#
|
55
52
|
# @api private
|
56
|
-
def initialize(type, value, **
|
53
|
+
def initialize(type, value, **)
|
57
54
|
super
|
58
55
|
@value = value
|
59
56
|
end
|
@@ -65,8 +62,8 @@ module Dry
|
|
65
62
|
# @return [Default]
|
66
63
|
#
|
67
64
|
# @api public
|
68
|
-
def constrained(
|
69
|
-
type.constrained(
|
65
|
+
def constrained(...)
|
66
|
+
type.constrained(...).default(value)
|
70
67
|
end
|
71
68
|
|
72
69
|
# @return [true]
|
data/lib/dry/types/enum.rb
CHANGED
data/lib/dry/types/errors.rb
CHANGED
@@ -51,6 +51,7 @@ module Dry
|
|
51
51
|
|
52
52
|
# @param [Array<CoercionError>] errors
|
53
53
|
def initialize(errors)
|
54
|
+
super("")
|
54
55
|
@errors = errors
|
55
56
|
end
|
56
57
|
|
@@ -66,11 +67,22 @@ module Dry
|
|
66
67
|
end
|
67
68
|
|
68
69
|
class SchemaError < CoercionError
|
70
|
+
# @return [String, Symbol]
|
71
|
+
attr_reader :key
|
72
|
+
|
73
|
+
# @return [Object]
|
74
|
+
attr_reader :value
|
75
|
+
|
69
76
|
# @param [String,Symbol] key
|
70
77
|
# @param [Object] value
|
71
78
|
# @param [String, #to_s] result
|
72
79
|
def initialize(key, value, result)
|
73
|
-
|
80
|
+
@key = key
|
81
|
+
@value = value
|
82
|
+
super(
|
83
|
+
"#{value.inspect} (#{value.class}) has invalid type "\
|
84
|
+
"for :#{key} violates constraints (#{result} failed)"
|
85
|
+
)
|
74
86
|
end
|
75
87
|
end
|
76
88
|
|
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/
|
4
|
-
require "dry/monads/
|
5
|
-
|
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
|
6
9
|
|
7
10
|
module Dry
|
8
11
|
module Types
|
@@ -15,7 +18,7 @@ module Dry
|
|
15
18
|
include Decorator
|
16
19
|
include Builder
|
17
20
|
include Printable
|
18
|
-
include ::Dry::Monads
|
21
|
+
include ::Dry::Monads[:maybe]
|
19
22
|
|
20
23
|
# @param [Dry::Monads::Maybe, Object] input
|
21
24
|
#
|
@@ -99,7 +102,7 @@ module Dry
|
|
99
102
|
end
|
100
103
|
|
101
104
|
# @api private
|
102
|
-
class Schema::Key
|
105
|
+
class Schema::Key # rubocop:disable Style/ClassAndModuleChildren
|
103
106
|
# @api private
|
104
107
|
def maybe
|
105
108
|
__new__(type.maybe)
|
@@ -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
|
#
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/types/constructor"
|
4
|
-
|
5
3
|
module Dry
|
6
4
|
module Types
|
7
5
|
# Hash type exposes additional APIs for working with schema hashes
|
@@ -24,8 +22,8 @@ module Dry
|
|
24
22
|
# @see Dry::Types::Array#of
|
25
23
|
#
|
26
24
|
# @api public
|
27
|
-
def schema(
|
28
|
-
type.schema(
|
25
|
+
def schema(...)
|
26
|
+
type.schema(...).constructor(fn, meta: meta)
|
29
27
|
end
|
30
28
|
end
|
31
29
|
end
|
data/lib/dry/types/hash.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/types/hash/constructor"
|
4
|
-
|
5
3
|
module Dry
|
6
4
|
module Types
|
7
5
|
# Hash types can be used to define maps and schemas
|
@@ -51,7 +49,7 @@ module Dry
|
|
51
49
|
# @api private
|
52
50
|
def weak(*)
|
53
51
|
raise "Support for old hash schemas was removed, please refer to the CHANGELOG "\
|
54
|
-
"on how to proceed with the new API https://github.com/dry-rb/dry-types/blob/
|
52
|
+
"on how to proceed with the new API https://github.com/dry-rb/dry-types/blob/main/CHANGELOG.md"
|
55
53
|
end
|
56
54
|
alias_method :permissive, :weak
|
57
55
|
alias_method :strict, :weak
|
@@ -132,6 +130,3 @@ module Dry
|
|
132
130
|
end
|
133
131
|
end
|
134
132
|
end
|
135
|
-
|
136
|
-
require "dry/types/schema/key"
|
137
|
-
require "dry/types/schema"
|
@@ -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/lax.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/core/deprecations"
|
4
|
-
require "dry/types/decorator"
|
5
|
-
|
6
3
|
module Dry
|
7
4
|
module Types
|
8
5
|
# Lax types rescue from type-related errors when constructors fail
|
@@ -68,7 +65,7 @@ module Dry
|
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
71
|
-
extend ::Dry::Core::Deprecations[:
|
68
|
+
extend ::Dry::Core::Deprecations[:"dry-types"]
|
72
69
|
Safe = Lax
|
73
70
|
deprecate_constant(:Safe)
|
74
71
|
end
|
data/lib/dry/types/map.rb
CHANGED
@@ -14,15 +14,17 @@ module Dry
|
|
14
14
|
# # => {1 => 'right'}
|
15
15
|
#
|
16
16
|
# type.('1' => 'wrong')
|
17
|
-
# # Dry::Types::MapError: "1" violates constraints (type?(Integer, "1")
|
17
|
+
# # Dry::Types::MapError: "1" violates constraints (type?(Integer, "1")
|
18
|
+
# # AND gteq?(1, "1")
|
19
|
+
# # AND lteq?(10, "1") failed)
|
18
20
|
#
|
19
21
|
# type.(11 => 'wrong')
|
20
22
|
# # Dry::Types::MapError: 11 violates constraints (lteq?(10, 11) failed)
|
21
23
|
#
|
22
24
|
# @api public
|
23
25
|
class Map < Nominal
|
24
|
-
def initialize(
|
25
|
-
super(
|
26
|
+
def initialize(primitive, key_type: Types["any"], value_type: Types["any"], meta: EMPTY_HASH)
|
27
|
+
super(primitive, key_type: key_type, value_type: value_type, meta: meta)
|
26
28
|
end
|
27
29
|
|
28
30
|
# @return [Type]
|
@@ -100,6 +102,8 @@ module Dry
|
|
100
102
|
private
|
101
103
|
|
102
104
|
# @api private
|
105
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
106
|
+
# rubocop:disable Metrics/AbcSize
|
103
107
|
def coerce(input)
|
104
108
|
unless primitive?(input)
|
105
109
|
return failure(
|
@@ -131,6 +135,8 @@ module Dry
|
|
131
135
|
failure(input, MultipleError.new(failures))
|
132
136
|
end
|
133
137
|
end
|
138
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
139
|
+
# rubocop:enable Metrics/AbcSize
|
134
140
|
end
|
135
141
|
end
|
136
142
|
end
|
data/lib/dry/types/module.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/core/deprecations"
|
4
3
|
require "dry/types/builder_methods"
|
5
4
|
|
6
5
|
module Dry
|
@@ -8,7 +7,7 @@ module Dry
|
|
8
7
|
# Export types registered in a container as module constants.
|
9
8
|
# @example
|
10
9
|
# module Types
|
11
|
-
# include Dry
|
10
|
+
# include Dry.Types(:strict, :coercible, :nominal, default: :strict)
|
12
11
|
# end
|
13
12
|
#
|
14
13
|
# Types.constants
|
@@ -26,10 +25,10 @@ module Dry
|
|
26
25
|
extend(BuilderMethods)
|
27
26
|
|
28
27
|
if constants.key?(:Nominal)
|
29
|
-
singleton_class.
|
28
|
+
singleton_class.define_method(:included) do |base|
|
30
29
|
super(base)
|
31
30
|
base.instance_exec(const_get(:Nominal, false)) do |nominal|
|
32
|
-
extend Dry::Core::Deprecations[:
|
31
|
+
extend Dry::Core::Deprecations[:"dry-types"]
|
33
32
|
const_set(:Definition, nominal)
|
34
33
|
deprecate_constant(:Definition, message: "Nominal")
|
35
34
|
end
|
@@ -38,13 +37,16 @@ module Dry
|
|
38
37
|
end
|
39
38
|
|
40
39
|
# @api private
|
40
|
+
# rubocop:disable Metrics/AbcSize
|
41
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
42
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
41
43
|
def type_constants(*namespaces, default: Undefined, **aliases)
|
42
44
|
if namespaces.empty? && aliases.empty? && Undefined.equal?(default)
|
43
45
|
default_ns = :Strict
|
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|
|
@@ -64,13 +68,16 @@ module Dry
|
|
64
68
|
constants.update(value) if key == default_ns
|
65
69
|
end
|
66
70
|
end
|
71
|
+
# rubocop:enable Metrics/AbcSize
|
72
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
73
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
67
74
|
|
68
75
|
# @api private
|
69
76
|
def registry_tree
|
70
77
|
@registry_tree ||= @registry.keys.each_with_object({}) { |key, tree|
|
71
78
|
type = @registry[key]
|
72
79
|
*modules, const_name = key.split(".").map { |part|
|
73
|
-
Inflector.camelize(part).to_sym
|
80
|
+
Types::Inflector.camelize(part).to_sym
|
74
81
|
}
|
75
82
|
next if modules.empty?
|
76
83
|
|
@@ -91,9 +98,11 @@ module Dry
|
|
91
98
|
ns.to_sym unless path.empty?
|
92
99
|
}.compact.uniq
|
93
100
|
|
94
|
-
(referenced.uniq - known).
|
101
|
+
unknown = (referenced.uniq - known).first
|
102
|
+
|
103
|
+
if unknown
|
95
104
|
raise ArgumentError,
|
96
|
-
"#{
|
105
|
+
"#{unknown.inspect} is not a known type namespace. "\
|
97
106
|
"Supported options are #{known.map(&:inspect).join(", ")}"
|
98
107
|
end
|
99
108
|
end
|
data/lib/dry/types/nominal.rb
CHANGED
@@ -1,12 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/core/deprecations"
|
4
|
-
require "dry/core/equalizer"
|
5
|
-
require "dry/types/builder"
|
6
|
-
require "dry/types/result"
|
7
|
-
require "dry/types/options"
|
8
|
-
require "dry/types/meta"
|
9
|
-
|
10
3
|
module Dry
|
11
4
|
module Types
|
12
5
|
# Nominal types define a primitive class and do not apply any constructors or constraints
|
@@ -20,7 +13,7 @@ module Dry
|
|
20
13
|
include Meta
|
21
14
|
include Builder
|
22
15
|
include Printable
|
23
|
-
include Dry::Equalizer(:primitive, :options, :meta, inspect: false, immutable: true)
|
16
|
+
include ::Dry::Equalizer(:primitive, :options, :meta, inspect: false, immutable: true)
|
24
17
|
|
25
18
|
# @return [Class]
|
26
19
|
attr_reader :primitive
|
@@ -199,12 +192,8 @@ module Dry
|
|
199
192
|
end
|
200
193
|
end
|
201
194
|
|
202
|
-
extend Dry::Core::Deprecations[:
|
195
|
+
extend ::Dry::Core::Deprecations[:"dry-types"]
|
203
196
|
Definition = Nominal
|
204
197
|
deprecate_constant(:Definition, message: "Nominal")
|
205
198
|
end
|
206
199
|
end
|
207
|
-
|
208
|
-
require "dry/types/array"
|
209
|
-
require "dry/types/hash"
|
210
|
-
require "dry/types/map"
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/core/cache"
|
4
|
-
require "dry/core/class_attributes"
|
5
|
-
require "dry/types/predicate_registry"
|
6
|
-
|
7
3
|
module Dry
|
8
4
|
module Types
|
9
5
|
# PredicateInferrer returns the list of predicates used by a type.
|
@@ -55,7 +51,7 @@ module Dry
|
|
55
51
|
end
|
56
52
|
|
57
53
|
# @api private
|
58
|
-
def infer_predicate(type)
|
54
|
+
def infer_predicate(type) # rubocop:disable Metrics/PerceivedComplexity
|
59
55
|
pred = TYPE_TO_PREDICATE.fetch(type) do
|
60
56
|
if type.name.nil? || self.class.infer_predicate_by_class_name.equal?(false)
|
61
57
|
nil
|
@@ -175,9 +171,9 @@ module Dry
|
|
175
171
|
def visit_predicate(node)
|
176
172
|
pred, args = node
|
177
173
|
|
178
|
-
if pred.equal?(:type?)
|
174
|
+
if pred.equal?(:type?) || !registry.key?(pred)
|
179
175
|
EMPTY_ARRAY
|
180
|
-
|
176
|
+
else
|
181
177
|
*curried, _ = args
|
182
178
|
values = curried.map { |_, v| v }
|
183
179
|
|
@@ -186,11 +182,14 @@ module Dry
|
|
186
182
|
else
|
187
183
|
[pred => values[0]]
|
188
184
|
end
|
189
|
-
else
|
190
|
-
EMPTY_ARRAY
|
191
185
|
end
|
192
186
|
end
|
193
187
|
|
188
|
+
# @api private
|
189
|
+
def visit_map(_node)
|
190
|
+
raise NotImplementedError, "map types are not supported yet"
|
191
|
+
end
|
192
|
+
|
194
193
|
private
|
195
194
|
|
196
195
|
# @api private
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/logic/predicates"
|
4
|
-
|
5
3
|
module Dry
|
6
4
|
module Types
|
7
5
|
# A registry with predicate objects from `Dry::Logic::Predicates`
|
@@ -14,20 +12,22 @@ module Dry
|
|
14
12
|
# @api private
|
15
13
|
attr_reader :has_predicate
|
16
14
|
|
15
|
+
KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
|
16
|
+
private_constant(:KERNEL_RESPOND_TO)
|
17
|
+
|
17
18
|
# @api private
|
18
19
|
def initialize(predicates = Logic::Predicates)
|
19
20
|
@predicates = predicates
|
20
|
-
@has_predicate = ::Kernel.instance_method(:respond_to?).bind(@predicates)
|
21
21
|
end
|
22
22
|
|
23
23
|
# @api private
|
24
|
-
def
|
25
|
-
predicates
|
24
|
+
def key?(name)
|
25
|
+
KERNEL_RESPOND_TO.bind_call(@predicates, name)
|
26
26
|
end
|
27
27
|
|
28
28
|
# @api private
|
29
|
-
def
|
30
|
-
|
29
|
+
def [](name)
|
30
|
+
predicates[name]
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -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
|