dry-types 1.7.2 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -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 +6 -10
  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