dry-types 1.8.3 → 1.9.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.
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2023 dry-rb team
3
+ Copyright (c) 2015-2026 Hanakai team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,23 +1,17 @@
1
- <!--- this file is synced from dry-rb/template-gem project -->
1
+ <!--- This file is synced from hanakai-rb/repo-sync -->
2
2
 
3
- [gem]: https://rubygems.org/gems/dry-types
3
+ [rubygem]: https://rubygems.org/gems/dry-types
4
4
  [actions]: https://github.com/dry-rb/dry-types/actions
5
5
 
6
- # dry-types [![Gem Version](https://badge.fury.io/rb/dry-types.svg)][gem] [![CI Status](https://github.com/dry-rb/dry-types/workflows/CI/badge.svg)][actions]
6
+ # dry-types [![Gem Version](https://badge.fury.io/rb/dry-types.svg)][rubygem] [![CI Status](https://github.com/dry-rb/dry-types/workflows/CI/badge.svg)][actions]
7
7
 
8
8
  ## Links
9
9
 
10
- * [User documentation](https://dry-rb.org/gems/dry-types)
11
- * [API documentation](http://rubydoc.info/gems/dry-types)
12
- * [Forum](https://discourse.dry-rb.org)
13
-
14
- ## Supported Ruby versions
15
-
16
- This library officially supports the following Ruby versions:
17
-
18
- * MRI `>= 3.1`
19
- * jruby `>= 9.4` (not tested on CI)
10
+ - [User documentation](https://dry-rb.org/gems/dry-types)
11
+ - [API documentation](http://rubydoc.info/gems/dry-types)
12
+ - [Forum](https://discourse.dry-rb.org)
20
13
 
21
14
  ## License
22
15
 
23
16
  See `LICENSE` file.
17
+
data/dry-types.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # this file is synced from dry-rb/template-gem project
3
+ # This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.
4
4
 
5
5
  lib = File.expand_path("lib", __dir__)
6
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -8,8 +8,8 @@ require "dry/types/version"
8
8
 
9
9
  Gem::Specification.new do |spec|
10
10
  spec.name = "dry-types"
11
- spec.authors = ["Piotr Solnica"]
12
- spec.email = ["piotr.solnica@gmail.com"]
11
+ spec.authors = ["Hanakai team"]
12
+ spec.email = ["info@hanakai.org"]
13
13
  spec.license = "MIT"
14
14
  spec.version = Dry::Types::VERSION.dup
15
15
 
@@ -21,19 +21,25 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = []
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
- spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-types/blob/main/CHANGELOG.md"
26
- spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-types"
27
- spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-types/issues"
28
- spec.metadata["rubygems_mfa_required"] = "true"
29
-
30
- spec.required_ruby_version = ">= 3.1"
31
-
32
- # to update dependencies edit project.yml
33
- spec.add_dependency "bigdecimal", "~> 3.0"
34
- spec.add_dependency "concurrent-ruby", "~> 1.0"
35
- spec.add_dependency "dry-core", "~> 1.0"
36
- spec.add_dependency "dry-inflector", "~> 1.0"
37
- spec.add_dependency "dry-logic", "~> 1.4"
38
- spec.add_dependency "zeitwerk", "~> 2.6"
24
+ spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
25
+
26
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
27
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-types/blob/main/CHANGELOG.md"
28
+ spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-types"
29
+ spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-types/issues"
30
+ spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
31
+
32
+ spec.required_ruby_version = ">= 3.2"
33
+
34
+ spec.add_runtime_dependency "bigdecimal", ">= 3.0"
35
+ spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
36
+ spec.add_runtime_dependency "dry-core", "~> 1.0"
37
+ spec.add_runtime_dependency "dry-inflector", "~> 1.0"
38
+ spec.add_runtime_dependency "dry-logic", "~> 1.4"
39
+ spec.add_runtime_dependency "zeitwerk", "~> 2.6"
40
+ spec.add_development_dependency "bundler"
41
+ spec.add_development_dependency "rake"
42
+ spec.add_development_dependency "rspec"
43
+ spec.add_development_dependency "yard"
39
44
  end
45
+
data/lib/dry/types/any.rb CHANGED
@@ -33,7 +33,7 @@ module Dry
33
33
  # @return [Array]
34
34
  #
35
35
  # @api public
36
- def to_ast(meta: true) = [:any, meta ? self.meta : EMPTY_HASH]
36
+ def to_ast(meta: true) = [:any, meta_ast(meta)]
37
37
  end
38
38
 
39
39
  Any = AnyClass.new
@@ -97,18 +97,16 @@ module Dry
97
97
  # @return [Lax]
98
98
  #
99
99
  # @api public
100
- def lax
101
- Lax.new(Member.new(primitive, **options, member: member.lax, meta: meta))
102
- end
100
+ def lax = Lax.new(Member.new(primitive, **options, member: member.lax, meta: meta))
103
101
 
104
102
  # @see Nominal#to_ast
105
103
  #
106
104
  # @api public
107
105
  def to_ast(meta: true)
108
106
  if member.respond_to?(:to_ast)
109
- [:array, [member.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
107
+ [:array, [member.to_ast(meta: meta), meta_ast(meta)]]
110
108
  else
111
- [:array, [member, meta ? self.meta : EMPTY_HASH]]
109
+ [:array, [member, meta_ast(meta)]]
112
110
  end
113
111
  end
114
112
 
@@ -50,7 +50,16 @@ module Dry
50
50
  # @return [Sum]
51
51
  #
52
52
  # @api public
53
- def optional = Types["nil"] | self
53
+ def optional
54
+ nil_type =
55
+ if Types.use_namespaced_optionals && respond_to?(:namespace) && namespace
56
+ Types["#{namespace}.nil"]
57
+ else
58
+ Types["nil"]
59
+ end
60
+
61
+ nil_type | self
62
+ end
54
63
 
55
64
  # Turn a type into a constrained type
56
65
  #
@@ -77,8 +86,15 @@ module Dry
77
86
  def default(input = Undefined, options = EMPTY_HASH, &block)
78
87
  unless input.frozen? || options[:shared]
79
88
  where = Core::Deprecations::STACK.()
89
+
90
+ # There is a weird behaviour in JRuby where the source_location is mutated upon
91
+ # calling `inspect` on proc (see: https://github.com/jruby/jruby/issues/9110)
92
+ # To bypass this, we call inspect on the clone (but only for proc and JRuby).
93
+ # This should be fixes in JRuby 10.0.3.0.
94
+ obj = input.is_a?(Proc) && RUBY_ENGINE == "jruby" ? input.dup : input
95
+
80
96
  Core::Deprecations.warn(
81
- "#{input.inspect} is mutable. " \
97
+ "#{obj.inspect} is mutable. " \
82
98
  "Be careful: types will return the same instance of the default " \
83
99
  "value every time. Call `.freeze` when setting the default " \
84
100
  "or pass `shared: true` to discard this warning." \
@@ -89,8 +89,8 @@ module Dry
89
89
  else
90
90
  Integer(input)
91
91
  end
92
- rescue ::ArgumentError, ::TypeError => e
93
- CoercionError.handle(e, &)
92
+ rescue ::ArgumentError, ::TypeError => exception
93
+ CoercionError.handle(exception, &)
94
94
  end
95
95
 
96
96
  # @param [#to_f, Object] input
@@ -102,8 +102,8 @@ module Dry
102
102
  # @api public
103
103
  def self.to_float(input, &)
104
104
  Float(input)
105
- rescue ::ArgumentError, ::TypeError => e
106
- CoercionError.handle(e, &)
105
+ rescue ::ArgumentError, ::TypeError => exception
106
+ CoercionError.handle(exception, &)
107
107
  end
108
108
 
109
109
  # @param [#to_d, Object] input
@@ -19,8 +19,8 @@ module Dry
19
19
  if input.respond_to?(:to_str)
20
20
  begin
21
21
  ::Date.parse(input)
22
- rescue ::ArgumentError, ::RangeError => e
23
- CoercionError.handle(e, &)
22
+ rescue ::ArgumentError, ::RangeError => exception
23
+ CoercionError.handle(exception, &)
24
24
  end
25
25
  elsif input.is_a?(::Date)
26
26
  input
@@ -42,8 +42,8 @@ module Dry
42
42
  if input.respond_to?(:to_str)
43
43
  begin
44
44
  ::DateTime.parse(input)
45
- rescue ::ArgumentError => e
46
- CoercionError.handle(e, &)
45
+ rescue ::ArgumentError => exception
46
+ CoercionError.handle(exception, &)
47
47
  end
48
48
  elsif input.is_a?(::DateTime)
49
49
  input
@@ -65,8 +65,8 @@ module Dry
65
65
  if input.respond_to?(:to_str)
66
66
  begin
67
67
  ::Time.parse(input)
68
- rescue ::ArgumentError => e
69
- CoercionError.handle(e, &)
68
+ rescue ::ArgumentError => exception
69
+ CoercionError.handle(exception, &)
70
70
  end
71
71
  elsif input.is_a?(::Time)
72
72
  input
@@ -86,8 +86,8 @@ module Dry
86
86
  # @api public
87
87
  def to_symbol(input, &)
88
88
  input.to_sym
89
- rescue ::NoMethodError => e
90
- CoercionError.handle(e, &)
89
+ rescue ::NoMethodError => exception
90
+ CoercionError.handle(exception, &)
91
91
  end
92
92
 
93
93
  private
@@ -37,13 +37,20 @@ module Dry
37
37
  deprecate(:visit_safe, :visit_lax)
38
38
 
39
39
  def visit_nominal(node)
40
- type, meta = node
40
+ type, options, meta =
41
+ case node
42
+ in [type, options, meta]
43
+ node
44
+ in [type, meta]
45
+ [type, EMPTY_HASH, meta]
46
+ end
47
+
41
48
  nominal_name = "nominal.#{Types.identifier(type)}"
42
49
 
43
50
  if registry.registered?(nominal_name)
44
- registry[nominal_name].meta(meta)
51
+ registry[nominal_name].with(**options).meta(meta)
45
52
  else
46
- Nominal.new(type, meta: meta)
53
+ Nominal.new(type, meta: meta, **options)
47
54
  end
48
55
  end
49
56
 
@@ -15,8 +15,8 @@ module Dry
15
15
  class Safe < Function
16
16
  def call(input, &)
17
17
  @fn.(input)
18
- rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
19
- CoercionError.handle(e, &)
18
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => exception
19
+ CoercionError.handle(exception, &)
20
20
  end
21
21
  end
22
22
 
@@ -92,8 +92,8 @@ module Dry
92
92
  class PrivateSafeCall < PrivateCall
93
93
  def call(input, &)
94
94
  @target.send(@name, input)
95
- rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
96
- CoercionError.handle(e, &)
95
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => exception
96
+ CoercionError.handle(exception, &)
97
97
  end
98
98
  end
99
99
 
@@ -120,8 +120,8 @@ module Dry
120
120
  # @return [Object]
121
121
  def call(input, type, &)
122
122
  @fn.(input, type, &)
123
- rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
124
- CoercionError.handle(e, &)
123
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => exception
124
+ CoercionError.handle(exception, &)
125
125
  end
126
126
  alias_method :[], :call
127
127
 
@@ -24,8 +24,8 @@ module Dry
24
24
  # @api public
25
25
  def try(input, &)
26
26
  value = fn.(input, type)
27
- rescue CoercionError => e
28
- failure = failure(input, e)
27
+ rescue CoercionError => exception
28
+ failure = failure(input, exception)
29
29
  block_given? ? yield(failure) : failure
30
30
  else
31
31
  type.try(value, &)
@@ -15,7 +15,7 @@ module Dry
15
15
  # @return [Type]
16
16
  attr_reader :type
17
17
 
18
- undef :constrained?, :meta, :optional?, :primitive, :default?, :name
18
+ undef :constrained?, :meta, :optional?, :primitive, :primitive?, :default?, :name, :namespace
19
19
 
20
20
  # @param [Builder, Object] input
21
21
  # @param [Hash] options
@@ -55,7 +55,7 @@ module Dry
55
55
  # Instantiate a new constructor type instance
56
56
  #
57
57
  # @param [Type] type
58
- # @param [Function] fn
58
+ # @option [Function] fn
59
59
  # @param [Hash] options
60
60
  #
61
61
  # @api private
@@ -88,8 +88,8 @@ module Dry
88
88
  # @api public
89
89
  def try(input, &)
90
90
  value = fn.(input)
91
- rescue CoercionError => e
92
- failure = failure(input, e)
91
+ rescue CoercionError => exception
92
+ failure = failure(input, exception)
93
93
  block_given? ? yield(failure) : failure
94
94
  else
95
95
  type.try(value, &)
@@ -94,8 +94,8 @@ module Dry
94
94
  # @api public
95
95
  def to_ast(meta: true)
96
96
  [:hash,
97
- [options.slice(:type_transform_fn),
98
- meta ? self.meta : EMPTY_HASH]]
97
+ [options.slice(:type_transform_fn, :namespace),
98
+ meta_ast(meta)]]
99
99
  end
100
100
 
101
101
  private
@@ -117,7 +117,7 @@ module Dry
117
117
  case type
118
118
  when Type then type
119
119
  when ::Class, ::String then Types[type]
120
- else type # rubocop:disable Lint/DuplicateBranch
120
+ else type
121
121
  end
122
122
  end
123
123
 
data/lib/dry/types/map.rb CHANGED
@@ -81,7 +81,7 @@ module Dry
81
81
  [:map,
82
82
  [key_type.to_ast(meta: true),
83
83
  value_type.to_ast(meta: true),
84
- meta ? self.meta : EMPTY_HASH]]
84
+ meta_ast(meta)]]
85
85
  end
86
86
 
87
87
  # @return [Boolean]
@@ -16,7 +16,13 @@ module Dry
16
16
  # @return [Type]
17
17
  #
18
18
  # @api public
19
- def with(**options) = super(meta: @meta, **options)
19
+ def with(**options)
20
+ if options.empty?
21
+ self
22
+ else
23
+ super(meta: @meta, **options)
24
+ end
25
+ end
20
26
 
21
27
  # @overload meta
22
28
  # @return [Hash] metadata associated with type
@@ -18,6 +18,9 @@ module Dry
18
18
  # @return [Class]
19
19
  attr_reader :primitive
20
20
 
21
+ # @return [String, nil]
22
+ attr_reader :namespace
23
+
21
24
  # @param [Class] primitive
22
25
  #
23
26
  # @return [Type]
@@ -42,6 +45,7 @@ module Dry
42
45
  def initialize(primitive, **options)
43
46
  super
44
47
  @primitive = primitive
48
+ @namespace = options[:namespace]
45
49
  freeze
46
50
  end
47
51
 
@@ -152,7 +156,7 @@ module Dry
152
156
  #
153
157
  # @api public
154
158
  def to_ast(meta: true)
155
- [:nominal, [primitive, meta ? self.meta : EMPTY_HASH]]
159
+ [:nominal, [primitive, namespace_ast, meta_ast(meta)]]
156
160
  end
157
161
 
158
162
  # Return self. Nominal types are lax by definition
@@ -168,6 +172,26 @@ module Dry
168
172
  #
169
173
  # @api public
170
174
  def to_proc = ALWAYS
175
+
176
+ private
177
+
178
+ # @api private
179
+ def namespace_ast
180
+ if @namespace
181
+ {namespace: @namespace}
182
+ else
183
+ EMPTY_HASH
184
+ end
185
+ end
186
+
187
+ # @api private
188
+ def meta_ast(meta)
189
+ if meta
190
+ self.meta
191
+ else
192
+ EMPTY_HASH
193
+ end
194
+ end
171
195
  end
172
196
 
173
197
  extend ::Dry::Core::Deprecations[:"dry-types"]
@@ -23,7 +23,11 @@ module Dry
23
23
  #
24
24
  # @api private
25
25
  def with(**new_options)
26
- self.class.new(*@__args__, **options, **new_options)
26
+ if new_options.empty?
27
+ self
28
+ else
29
+ self.class.new(*@__args__, **options, **new_options)
30
+ end
27
31
  end
28
32
  end
29
33
  end
@@ -4,63 +4,34 @@ require "dry/types/coercions/params"
4
4
 
5
5
  module Dry
6
6
  module Types
7
- register("params.nil") do
8
- self["nominal.nil"].constructor(Coercions::Params.method(:to_nil))
9
- end
10
-
11
- register("params.date") do
12
- self["nominal.date"].constructor(Coercions::Params.method(:to_date))
13
- end
14
-
15
- register("params.date_time") do
16
- self["nominal.date_time"].constructor(Coercions::Params.method(:to_date_time))
17
- end
18
-
19
- register("params.time") do
20
- self["nominal.time"].constructor(Coercions::Params.method(:to_time))
21
- end
22
-
23
- register("params.true") do
24
- self["nominal.true"].constructor(Coercions::Params.method(:to_true))
25
- end
26
-
27
- register("params.false") do
28
- self["nominal.false"].constructor(Coercions::Params.method(:to_false))
7
+ options = {namespace: "params"}
8
+
9
+ {
10
+ "nil" => :to_nil,
11
+ "date" => :to_date,
12
+ "date_time" => :to_date_time,
13
+ "time" => :to_time,
14
+ "true" => :to_true,
15
+ "false" => :to_false,
16
+ "integer" => :to_int,
17
+ "float" => :to_float,
18
+ "decimal" => :to_decimal,
19
+ "array" => :to_ary,
20
+ "hash" => :to_hash,
21
+ "symbol" => :to_symbol
22
+ }.each do |name, method|
23
+ register("params.#{name}") do
24
+ self["nominal.#{name}"].with(**options).constructor(Coercions::Params.method(method))
25
+ end
29
26
  end
30
27
 
31
28
  register("params.bool") do
32
29
  self["params.true"] | self["params.false"]
33
30
  end
34
31
 
35
- register("params.integer") do
36
- self["nominal.integer"].constructor(Coercions::Params.method(:to_int))
37
- end
38
-
39
- register("params.float") do
40
- self["nominal.float"].constructor(Coercions::Params.method(:to_float))
41
- end
42
-
43
- register("params.decimal") do
44
- self["nominal.decimal"].constructor(Coercions::Params.method(:to_decimal))
45
- end
46
-
47
- register("params.array") do
48
- self["nominal.array"].constructor(Coercions::Params.method(:to_ary))
49
- end
50
-
51
- register("params.hash") do
52
- self["nominal.hash"].constructor(Coercions::Params.method(:to_hash))
53
- end
54
-
55
- register("params.symbol") do
56
- self["nominal.symbol"].constructor(Coercions::Params.method(:to_symbol))
57
- end
58
-
59
- register("params.string", self["string"])
32
+ register("params.string", self["string"].with(**options))
60
33
 
61
34
  COERCIBLE.each_key do |name|
62
- next if name.equal?(:string)
63
-
64
35
  register("optional.params.#{name}", self["params.nil"] | self["params.#{name}"])
65
36
  end
66
37
  end
@@ -137,7 +137,7 @@ module Dry
137
137
  left = visit(left_node)
138
138
  right = visit(right_node)
139
139
 
140
- if left.eql?(NIL) # rubocop:disable Lint/DeprecatedConstants
140
+ if left.eql?(NIL)
141
141
  right
142
142
  else
143
143
  [[left, right]]
@@ -19,10 +19,7 @@ module Dry
19
19
  end
20
20
 
21
21
  # @api private
22
- def visit_nominal(node)
23
- type, _ = node
24
- type
25
- end
22
+ def visit_nominal(node) = node[0]
26
23
 
27
24
  # @api private
28
25
  def visit_hash(_) = ::Hash
@@ -35,16 +32,10 @@ module Dry
35
32
  def visit_lax(node) = visit(node)
36
33
 
37
34
  # @api private
38
- def visit_constructor(node)
39
- other, * = node
40
- visit(other)
41
- end
35
+ def visit_constructor(node) = visit(node[0])
42
36
 
43
37
  # @api private
44
- def visit_enum(node)
45
- other, * = node
46
- visit(other)
47
- end
38
+ def visit_enum(node) = visit(node[0])
48
39
 
49
40
  # @api private
50
41
  def visit_sum(node)
@@ -54,10 +45,7 @@ module Dry
54
45
  end
55
46
 
56
47
  # @api private
57
- def visit_constrained(node)
58
- other, * = node
59
- visit(other)
60
- end
48
+ def visit_constrained(node) = visit(node[0])
61
49
 
62
50
  # @api private
63
51
  def visit_any(_) = ::Object
@@ -105,6 +105,22 @@ module Dry
105
105
  @composition_printers[klass].visit(composition, &)
106
106
  end
107
107
 
108
+ def visit_sum_constructors(sum)
109
+ visit_sum_constructor(sum.left) do |left|
110
+ visit_sum_constructor(sum.right) do |right|
111
+ yield "#{left} #{sum.class.operator} #{right}"
112
+ end
113
+ end
114
+ end
115
+
116
+ def visit_sum_constructor(type, &)
117
+ if type.is_a?(Dry::Types::Sum)
118
+ visit_sum_constructors(type, &)
119
+ else
120
+ visit(type, &)
121
+ end
122
+ end
123
+
108
124
  def visit_enum(enum)
109
125
  visit(enum.type) do |type|
110
126
  options = enum.options.dup
@@ -163,7 +179,7 @@ module Dry
163
179
  elsif path
164
180
  yield "#{path.sub("#{Dir.pwd}/", EMPTY_STRING)}:#{line}"
165
181
  else
166
- match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(?<name>\w+)\)(:? \(lambda\))?>\z/) # rubocop:disable Lint/MixedRegexpCaptureTypes
182
+ match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(?<name>\w+)\)(:? \(lambda\))?>\z/)
167
183
 
168
184
  if match
169
185
  yield ".#{match[:name]}"
@@ -148,8 +148,8 @@ module Dry
148
148
  [
149
149
  :schema,
150
150
  [keys.map { |key| key.to_ast(meta: meta) },
151
- options.slice(:key_transform_fn, :type_transform_fn, :strict),
152
- meta ? self.meta : EMPTY_HASH]
151
+ options.slice(:key_transform_fn, :type_transform_fn, :strict, :namespace),
152
+ meta_ast(meta)]
153
153
  ]
154
154
  end
155
155
 
@@ -167,7 +167,7 @@ module Dry
167
167
  # @return [Schema]
168
168
  #
169
169
  # @api public
170
- def strict(strict = true) # rubocop:disable Style/OptionalBooleanParameter
170
+ def strict(strict = true)
171
171
  with(strict: strict)
172
172
  end
173
173
 
@@ -326,10 +326,10 @@ module Dry
326
326
  if type
327
327
  begin
328
328
  result[k] = type.call_unsafe(value)
329
- rescue ConstraintError => e
330
- raise SchemaError.new(type.name, value, e.result)
331
- rescue CoercionError => e
332
- raise SchemaError.new(type.name, value, e.message)
329
+ rescue ConstraintError => exception
330
+ raise SchemaError.new(type.name, value, exception.result)
331
+ rescue CoercionError => exception
332
+ raise SchemaError.new(type.name, value, exception.message)
333
333
  end
334
334
  elsif strict?
335
335
  raise unexpected_keys(hash.keys)