dry-types 1.7.2 → 1.8.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +1 -1
  4. data/dry-types.gemspec +12 -16
  5. data/lib/dry/types/any.rb +3 -9
  6. data/lib/dry/types/array/constructor.rb +3 -9
  7. data/lib/dry/types/array/member.rb +1 -3
  8. data/lib/dry/types/array.rb +1 -1
  9. data/lib/dry/types/builder.rb +19 -35
  10. data/lib/dry/types/builder_methods.rb +5 -15
  11. data/lib/dry/types/coercions/json.rb +3 -3
  12. data/lib/dry/types/coercions/params.rb +13 -13
  13. data/lib/dry/types/coercions.rb +13 -15
  14. data/lib/dry/types/compiler.rb +5 -7
  15. data/lib/dry/types/composition.rb +17 -31
  16. data/lib/dry/types/constrained/coercible.rb +3 -3
  17. data/lib/dry/types/constrained.rb +31 -23
  18. data/lib/dry/types/constructor/function.rb +19 -31
  19. data/lib/dry/types/constructor/wrapper.rb +5 -11
  20. data/lib/dry/types/constructor.rb +9 -17
  21. data/lib/dry/types/core.rb +14 -6
  22. data/lib/dry/types/decorator.rb +7 -18
  23. data/lib/dry/types/default.rb +14 -18
  24. data/lib/dry/types/enum.rb +33 -13
  25. data/lib/dry/types/errors.rb +4 -8
  26. data/lib/dry/types/extensions/maybe.rb +5 -11
  27. data/lib/dry/types/fn_container.rb +3 -3
  28. data/lib/dry/types/hash/constructor.rb +3 -9
  29. data/lib/dry/types/hash.rb +8 -6
  30. data/lib/dry/types/implication.rb +5 -7
  31. data/lib/dry/types/inflector.rb +1 -1
  32. data/lib/dry/types/intersection.rb +3 -9
  33. data/lib/dry/types/lax.rb +5 -11
  34. data/lib/dry/types/map.rb +33 -41
  35. data/lib/dry/types/meta.rb +2 -6
  36. data/lib/dry/types/module.rb +3 -5
  37. data/lib/dry/types/nominal.rb +13 -35
  38. data/lib/dry/types/predicate_inferrer.rb +3 -5
  39. data/lib/dry/types/predicate_registry.rb +1 -3
  40. data/lib/dry/types/primitive_inferrer.rb +4 -12
  41. data/lib/dry/types/printable.rb +1 -3
  42. data/lib/dry/types/printer/composition.rb +3 -3
  43. data/lib/dry/types/printer.rb +6 -9
  44. data/lib/dry/types/result.rb +5 -15
  45. data/lib/dry/types/schema/key.rb +11 -26
  46. data/lib/dry/types/schema.rb +10 -12
  47. data/lib/dry/types/spec/types.rb +2 -2
  48. data/lib/dry/types/sum.rb +4 -8
  49. data/lib/dry/types/type.rb +2 -2
  50. data/lib/dry/types/version.rb +1 -1
  51. data/lib/dry/types.rb +2 -2
  52. metadata +8 -63
@@ -8,7 +8,7 @@ module Dry
8
8
  class Default
9
9
  # @api private
10
10
  class Callable < Default
11
- include Dry::Equalizer(:type, inspect: false, immutable: true)
11
+ include ::Dry::Equalizer(:type, inspect: false, immutable: true)
12
12
 
13
13
  # Evaluates given callable
14
14
  # @return [Object]
@@ -26,7 +26,7 @@ module Dry
26
26
  include Decorator
27
27
  include Builder
28
28
  include Printable
29
- include Dry::Equalizer(:type, :value, inspect: false, immutable: true)
29
+ include ::Dry::Equalizer(:type, :value, inspect: false, immutable: true)
30
30
 
31
31
  # @return [Object]
32
32
  attr_reader :value
@@ -62,32 +62,30 @@ module Dry
62
62
  # @return [Default]
63
63
  #
64
64
  # @api public
65
- def constrained(...)
66
- type.constrained(...).default(value)
67
- end
65
+ def constrained(...) = type.constrained(...).default(value)
68
66
 
69
67
  # @return [true]
70
68
  #
71
69
  # @api public
72
- def default?
73
- true
74
- end
70
+ def default? = true
75
71
 
76
72
  # @param [Object] input
77
73
  #
78
74
  # @return [Result::Success]
79
75
  #
80
76
  # @api public
81
- def try(input)
82
- success(call(input))
77
+ def try(input = Undefined, &)
78
+ if input.equal?(Undefined)
79
+ success(evaluate)
80
+ else
81
+ type.try(input)
82
+ end
83
83
  end
84
84
 
85
85
  # @return [Boolean]
86
86
  #
87
87
  # @api public
88
- def valid?(value = Undefined)
89
- Undefined.equal?(value) || super
90
- end
88
+ def valid?(value = Undefined) = Undefined.equal?(value) || super
91
89
 
92
90
  # @param [Object] input
93
91
  #
@@ -107,20 +105,18 @@ module Dry
107
105
  # @return [Object] value passed through {#type} or {#default} value
108
106
  #
109
107
  # @api private
110
- def call_safe(input = Undefined, &block)
108
+ def call_safe(input = Undefined, &)
111
109
  if input.equal?(Undefined)
112
110
  evaluate
113
111
  else
114
- Undefined.default(type.call_safe(input, &block)) { evaluate }
112
+ Undefined.default(type.call_safe(input, &)) { evaluate }
115
113
  end
116
114
  end
117
115
 
118
116
  # @return [false]
119
117
  #
120
118
  # @api private
121
- def callable?
122
- false
123
- end
119
+ def callable? = false
124
120
  end
125
121
  end
126
122
  end
@@ -7,7 +7,7 @@ module Dry
7
7
  # @api public
8
8
  class Enum
9
9
  include Type
10
- include Dry::Equalizer(:type, :mapping, inspect: false, immutable: true)
10
+ include ::Dry::Equalizer(:type, :mapping, inspect: false, immutable: true)
11
11
  include Decorator
12
12
  include Builder
13
13
 
@@ -36,27 +36,21 @@ module Dry
36
36
  # @return [Object]
37
37
  #
38
38
  # @api private
39
- def call_unsafe(input)
40
- type.call_unsafe(map_value(input))
41
- end
39
+ def call_unsafe(input) = type.call_unsafe(map_value(input))
42
40
 
43
41
  # @return [Object]
44
42
  #
45
43
  # @api private
46
- def call_safe(input, &block)
47
- type.call_safe(map_value(input), &block)
48
- end
44
+ def call_safe(input, &) = type.call_safe(map_value(input), &)
49
45
 
50
46
  # @see Dry::Types::Constrained#try
51
47
  #
52
48
  # @api public
53
- def try(input)
54
- super(map_value(input))
55
- end
49
+ def try(input, &) = super(map_value(input))
56
50
 
57
51
  # @api private
58
52
  def default(*)
59
- raise ".enum(*values).default(value) is not supported. Call "\
53
+ raise ".enum(*values).default(value) is not supported. Call " \
60
54
  ".default(value).enum(*values) instead"
61
55
  end
62
56
 
@@ -73,11 +67,37 @@ module Dry
73
67
  # @return [String]
74
68
  #
75
69
  # @api public
76
- def to_s
77
- PRINTER.(self)
70
+ def to_s = PRINTER.(self)
71
+
72
+ # Iterate over each enum value
73
+ #
74
+ # @return [Array, Enumerator]
75
+ #
76
+ # @api public
77
+ def each_value(&)
78
+ values.each(&)
78
79
  end
80
+
79
81
  alias_method :inspect, :to_s
80
82
 
83
+ # @return [String]
84
+ #
85
+ # @api public
86
+ def name = "#{super}(#{joined_values})"
87
+
88
+ # @return [String]
89
+ #
90
+ # @api private
91
+ def joined_values
92
+ mapping.keys.map { |value|
93
+ if value.is_a?(::String)
94
+ value
95
+ else
96
+ value.inspect
97
+ end
98
+ }.join("|")
99
+ end
100
+
81
101
  private
82
102
 
83
103
  # Maps a value
@@ -56,14 +56,10 @@ module Dry
56
56
  end
57
57
 
58
58
  # @return string
59
- def message
60
- errors.map(&:message).join(", ")
61
- end
59
+ def message = errors.map(&:message).join(", ")
62
60
 
63
61
  # @return [Array]
64
- def meta
65
- errors.map(&:meta)
66
- end
62
+ def meta = errors.map(&:meta)
67
63
  end
68
64
 
69
65
  class SchemaError < CoercionError
@@ -80,7 +76,7 @@ module Dry
80
76
  @key = key
81
77
  @value = value
82
78
  super(
83
- "#{value.inspect} (#{value.class}) has invalid type "\
79
+ "#{value.inspect} (#{value.class}) has invalid type " \
84
80
  "for :#{key} violates constraints (#{result} failed)"
85
81
  )
86
82
  end
@@ -125,7 +121,7 @@ module Dry
125
121
  @result = result
126
122
  @input = input
127
123
 
128
- if result.is_a?(String)
124
+ if result.is_a?(::String)
129
125
  super(result)
130
126
  else
131
127
  super(to_s)
@@ -57,7 +57,7 @@ module Dry
57
57
  # @return [Result::Success]
58
58
  #
59
59
  # @api public
60
- def try(input = Undefined)
60
+ def try(input = Undefined, &)
61
61
  result = type.try(input)
62
62
 
63
63
  if result.success?
@@ -70,9 +70,7 @@ module Dry
70
70
  # @return [true]
71
71
  #
72
72
  # @api public
73
- def default?
74
- true
75
- end
73
+ def default? = true
76
74
 
77
75
  # @param [Object] value
78
76
  #
@@ -83,7 +81,7 @@ module Dry
83
81
  # @api public
84
82
  def default(value)
85
83
  if value.nil?
86
- raise ArgumentError, "nil cannot be used as a default of a maybe type"
84
+ raise ::ArgumentError, "nil cannot be used as a default of a maybe type"
87
85
  else
88
86
  super
89
87
  end
@@ -96,17 +94,13 @@ module Dry
96
94
  # @return [Maybe]
97
95
  #
98
96
  # @api public
99
- def maybe
100
- Maybe.new(Types["nil"] | self)
101
- end
97
+ def maybe = Maybe.new(Types["nil"] | self)
102
98
  end
103
99
 
104
100
  # @api private
105
101
  class Schema::Key # rubocop:disable Style/ClassAndModuleChildren
106
102
  # @api private
107
- def maybe
108
- __new__(type.maybe)
109
- end
103
+ def maybe = __new__(type.maybe)
110
104
  end
111
105
 
112
106
  # @api private
@@ -12,8 +12,8 @@ module Dry
12
12
  end
13
13
 
14
14
  # @api private
15
- def self.register(function = Dry::Core::Constants::Undefined, &block)
16
- fn = Dry::Core::Constants::Undefined.default(function, block)
15
+ def self.register(function = ::Dry::Core::Constants::Undefined, &block)
16
+ fn = ::Dry::Core::Constants::Undefined.default(function, block)
17
17
  fn_name = register_name(fn)
18
18
  container.register(fn_name, fn) unless container.key?(fn_name)
19
19
  fn_name
@@ -30,7 +30,7 @@ module Dry
30
30
 
31
31
  # @api private
32
32
  def self.register_name(function)
33
- "fn_#{function.object_id}"
33
+ "fn_#{function.__id__}"
34
34
  end
35
35
  end
36
36
  end
@@ -8,23 +8,17 @@ module Dry
8
8
  class Hash < Nominal
9
9
  class Constructor < ::Dry::Types::Constructor
10
10
  # @api private
11
- def constructor_type
12
- ::Dry::Types::Hash::Constructor
13
- end
11
+ def constructor_type = ::Dry::Types::Hash::Constructor
14
12
 
15
13
  # @return [Lax]
16
14
  #
17
15
  # @api public
18
- def lax
19
- type.lax.constructor(fn, meta: meta)
20
- end
16
+ def lax = Lax.new(type.lax.constructor(fn, meta: meta))
21
17
 
22
18
  # @see Dry::Types::Array#of
23
19
  #
24
20
  # @api public
25
- def schema(...)
26
- type.schema(...).constructor(fn, meta: meta)
27
- end
21
+ def schema(...) = type.schema(...).constructor(fn, meta: meta)
28
22
  end
29
23
  end
30
24
  end
@@ -48,7 +48,7 @@ module Dry
48
48
 
49
49
  # @api private
50
50
  def weak(*)
51
- raise "Support for old hash schemas was removed, please refer to the CHANGELOG "\
51
+ raise "Support for old hash schemas was removed, please refer to the CHANGELOG " \
52
52
  "on how to proceed with the new API https://github.com/dry-rb/dry-types/blob/main/CHANGELOG.md"
53
53
  end
54
54
  alias_method :permissive, :weak
@@ -67,9 +67,9 @@ module Dry
67
67
  def with_type_transform(proc = nil, &block)
68
68
  fn = proc || block
69
69
 
70
- raise ArgumentError, "a block or callable argument is required" if fn.nil?
70
+ raise ::ArgumentError, "a block or callable argument is required" if fn.nil?
71
71
 
72
- handle = Dry::Types::FnContainer.register(fn)
72
+ handle = ::Dry::Types::FnContainer.register(fn)
73
73
  with(type_transform_fn: handle)
74
74
  end
75
75
 
@@ -93,7 +93,9 @@ module Dry
93
93
  #
94
94
  # @api public
95
95
  def to_ast(meta: true)
96
- [:hash, [options.slice(:type_transform_fn), meta ? self.meta : EMPTY_HASH]]
96
+ [:hash,
97
+ [options.slice(:type_transform_fn),
98
+ meta ? self.meta : EMPTY_HASH]]
97
99
  end
98
100
 
99
101
  private
@@ -101,7 +103,7 @@ module Dry
101
103
  # @api private
102
104
  def build_keys(type_map)
103
105
  type_fn = options.fetch(:type_transform_fn, Schema::NO_TRANSFORM)
104
- type_transform = Dry::Types::FnContainer[type_fn]
106
+ type_transform = ::Dry::Types::FnContainer[type_fn]
105
107
 
106
108
  type_map.map do |map_key, type|
107
109
  name, options = key_name(map_key)
@@ -115,7 +117,7 @@ module Dry
115
117
  case type
116
118
  when Type then type
117
119
  when ::Class, ::String then Types[type]
118
- else type
120
+ else type # rubocop:disable Lint/DuplicateBranch
119
121
  end
120
122
  end
121
123
 
@@ -8,9 +8,7 @@ module Dry
8
8
  class Implication
9
9
  include Composition
10
10
 
11
- def self.operator
12
- :>
13
- end
11
+ def self.operator = :>
14
12
 
15
13
  # @param [Object] input
16
14
  #
@@ -30,9 +28,9 @@ module Dry
30
28
  # @return [Object]
31
29
  #
32
30
  # @api private
33
- def call_safe(input, &block)
31
+ def call_safe(input, &)
34
32
  if left.try(input).success?
35
- right.call_safe(input, &block)
33
+ right.call_safe(input, &)
36
34
  else
37
35
  input
38
36
  end
@@ -41,9 +39,9 @@ module Dry
41
39
  # @param [Object] input
42
40
  #
43
41
  # @api public
44
- def try(input)
42
+ def try(input, &)
45
43
  if left.try(input).success?
46
- right.try(input)
44
+ right.try(input, &)
47
45
  else
48
46
  Result::Success.new(input)
49
47
  end
@@ -4,6 +4,6 @@ require "dry/inflector"
4
4
 
5
5
  module Dry
6
6
  module Types
7
- Inflector = Dry::Inflector.new
7
+ Inflector = ::Dry::Inflector.new
8
8
  end
9
9
  end
@@ -12,9 +12,7 @@ module Dry
12
12
  class Intersection
13
13
  include Composition
14
14
 
15
- def self.operator
16
- :&
17
- end
15
+ def self.operator = :&
18
16
 
19
17
  # @param [Object] input
20
18
  #
@@ -30,9 +28,7 @@ module Dry
30
28
  # @return [Object]
31
29
  #
32
30
  # @api private
33
- def call_safe(input, &block)
34
- try_sides(input, &block).input
35
- end
31
+ def call_safe(input, &) = try_sides(input, &).input
36
32
 
37
33
  # @param [Object] input
38
34
  #
@@ -94,9 +90,7 @@ module Dry
94
90
  def merge_results(left_result, right_result)
95
91
  case left_result
96
92
  when ::Array
97
- left_result
98
- .zip(right_result)
99
- .map { |lhs, rhs| merge_results(lhs, rhs) }
93
+ left_result.zip(right_result).map { merge_results(_1, _2) }
100
94
  when ::Hash
101
95
  left_result.merge(right_result)
102
96
  else
data/lib/dry/types/lax.rb CHANGED
@@ -10,7 +10,7 @@ module Dry
10
10
  include Decorator
11
11
  include Builder
12
12
  include Printable
13
- include Dry::Equalizer(:type, inspect: false, immutable: true)
13
+ include ::Dry::Equalizer(:type, inspect: false, immutable: true)
14
14
 
15
15
  undef :options, :constructor, :<<, :>>, :prepend, :append
16
16
 
@@ -19,7 +19,7 @@ module Dry
19
19
  # @return [Object]
20
20
  #
21
21
  # @api public
22
- def call(input)
22
+ def call(input, &)
23
23
  type.call_safe(input) { |output = input| output }
24
24
  end
25
25
  alias_method :[], :call
@@ -35,23 +35,17 @@ module Dry
35
35
  # @return [Result,Logic::Result]
36
36
  #
37
37
  # @api public
38
- def try(input, &block)
39
- type.try(input, &block)
40
- end
38
+ def try(input, &) = type.try(input, &)
41
39
 
42
40
  # @see Nominal#to_ast
43
41
  #
44
42
  # @api public
45
- def to_ast(meta: true)
46
- [:lax, type.to_ast(meta: meta)]
47
- end
43
+ def to_ast(meta: true) = [:lax, type.to_ast(meta: meta)]
48
44
 
49
45
  # @return [Lax]
50
46
  #
51
47
  # @api public
52
- def lax
53
- self
54
- end
48
+ def lax = self
55
49
 
56
50
  private
57
51
 
data/lib/dry/types/map.rb CHANGED
@@ -24,29 +24,23 @@ module Dry
24
24
  # @api public
25
25
  class Map < Nominal
26
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)
27
+ super
28
28
  end
29
29
 
30
30
  # @return [Type]
31
31
  #
32
32
  # @api public
33
- def key_type
34
- options[:key_type]
35
- end
33
+ def key_type = options[:key_type]
36
34
 
37
35
  # @return [Type]
38
36
  #
39
37
  # @api public
40
- def value_type
41
- options[:value_type]
42
- end
38
+ def value_type = options[:value_type]
43
39
 
44
40
  # @return [String]
45
41
  #
46
42
  # @api public
47
- def name
48
- "Map"
49
- end
43
+ def name = "Map"
50
44
 
51
45
  # @param [Hash] hash
52
46
  #
@@ -64,9 +58,7 @@ module Dry
64
58
  # @return [Hash]
65
59
  #
66
60
  # @api private
67
- def call_safe(hash)
68
- try(hash) { return yield }.input
69
- end
61
+ def call_safe(hash) = try(hash) { return yield }.input
70
62
 
71
63
  # @param [Hash] hash
72
64
  #
@@ -95,48 +87,48 @@ module Dry
95
87
  # @return [Boolean]
96
88
  #
97
89
  # @api public
98
- def constrained?
99
- value_type.constrained?
100
- end
90
+ def constrained? = value_type.constrained?
101
91
 
102
92
  private
103
93
 
104
94
  # @api private
105
- # rubocop:disable Metrics/PerceivedComplexity
106
95
  # rubocop:disable Metrics/AbcSize
107
96
  def coerce(input)
108
- unless primitive?(input)
109
- return failure(
110
- input, CoercionError.new("#{input.inspect} must be an instance of #{primitive}")
111
- )
112
- end
113
-
114
- output = {}
115
- failures = []
116
-
117
- input.each do |k, v|
118
- res_k = key_type.try(k)
119
- res_v = value_type.try(v)
97
+ assert_primitive(input) do
98
+ output = {}
99
+ failures = []
100
+
101
+ input.each do |k, v|
102
+ res_k = key_type.try(k)
103
+ res_v = value_type.try(v)
104
+
105
+ if res_k.failure?
106
+ failures << res_k.error
107
+ elsif output.key?(res_k.input)
108
+ failures << CoercionError.new("duplicate coerced hash key #{res_k.input.inspect}")
109
+ elsif res_v.failure?
110
+ failures << res_v.error
111
+ else
112
+ output[res_k.input] = res_v.input
113
+ end
114
+ end
120
115
 
121
- if res_k.failure?
122
- failures << res_k.error
123
- elsif output.key?(res_k.input)
124
- failures << CoercionError.new("duplicate coerced hash key #{res_k.input.inspect}")
125
- elsif res_v.failure?
126
- failures << res_v.error
116
+ if failures.empty?
117
+ success(output)
127
118
  else
128
- output[res_k.input] = res_v.input
119
+ failure(input, MultipleError.new(failures))
129
120
  end
130
121
  end
122
+ end
123
+ # rubocop:enable Metrics/AbcSize
131
124
 
132
- if failures.empty?
133
- success(output)
125
+ def assert_primitive(input)
126
+ if primitive?(input)
127
+ yield
134
128
  else
135
- failure(input, MultipleError.new(failures))
129
+ failure(input, CoercionError.new("#{input.inspect} must be an instance of #{primitive}"))
136
130
  end
137
131
  end
138
- # rubocop:enable Metrics/PerceivedComplexity
139
- # rubocop:enable Metrics/AbcSize
140
132
  end
141
133
  end
142
134
  end
@@ -16,9 +16,7 @@ module Dry
16
16
  # @return [Type]
17
17
  #
18
18
  # @api public
19
- def with(**options)
20
- super(meta: @meta, **options)
21
- end
19
+ def with(**options) = super(meta: @meta, **options)
22
20
 
23
21
  # @overload meta
24
22
  # @return [Hash] metadata associated with type
@@ -43,9 +41,7 @@ module Dry
43
41
  # @return [Dry::Types::Type]
44
42
  #
45
43
  # @api public
46
- def pristine
47
- with(meta: EMPTY_HASH)
48
- end
44
+ def pristine = with(meta: EMPTY_HASH)
49
45
  end
50
46
  end
51
47
  end
@@ -38,7 +38,6 @@ module Dry
38
38
 
39
39
  # @api private
40
40
  # rubocop:disable Metrics/AbcSize
41
- # rubocop:disable Metrics/CyclomaticComplexity
42
41
  # rubocop:disable Metrics/PerceivedComplexity
43
42
  def type_constants(*namespaces, default: Undefined, **aliases)
44
43
  if namespaces.empty? && aliases.empty? && Undefined.equal?(default)
@@ -52,7 +51,7 @@ module Dry
52
51
  tree = registry_tree
53
52
 
54
53
  if namespaces.empty? && aliases.empty?
55
- modules = tree.select { |_, v| v.is_a?(::Hash) }.map(&:first)
54
+ modules = tree.select { _2.is_a?(::Hash) }.map(&:first)
56
55
  else
57
56
  modules = (namespaces + aliases.keys).map { |n|
58
57
  Types::Inflector.camelize(n).to_sym
@@ -69,7 +68,6 @@ module Dry
69
68
  end
70
69
  end
71
70
  # rubocop:enable Metrics/AbcSize
72
- # rubocop:enable Metrics/CyclomaticComplexity
73
71
  # rubocop:enable Metrics/PerceivedComplexity
74
72
 
75
73
  # @api private
@@ -101,8 +99,8 @@ module Dry
101
99
  unknown = (referenced.uniq - known).first
102
100
 
103
101
  if unknown
104
- raise ArgumentError,
105
- "#{unknown.inspect} is not a known type namespace. "\
102
+ raise ::ArgumentError,
103
+ "#{unknown.inspect} is not a known type namespace. " \
106
104
  "Supported options are #{known.map(&:inspect).join(", ")}"
107
105
  end
108
106
  end