dry-types 0.13.2 → 1.5.1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +763 -233
  3. data/LICENSE +17 -17
  4. data/README.md +15 -13
  5. data/dry-types.gemspec +28 -28
  6. data/lib/dry-types.rb +3 -1
  7. data/lib/dry/types.rb +156 -76
  8. data/lib/dry/types/any.rb +32 -12
  9. data/lib/dry/types/array.rb +19 -6
  10. data/lib/dry/types/array/constructor.rb +32 -0
  11. data/lib/dry/types/array/member.rb +75 -16
  12. data/lib/dry/types/builder.rb +131 -15
  13. data/lib/dry/types/builder_methods.rb +49 -20
  14. data/lib/dry/types/coercions.rb +76 -22
  15. data/lib/dry/types/coercions/json.rb +43 -7
  16. data/lib/dry/types/coercions/params.rb +118 -31
  17. data/lib/dry/types/compat.rb +0 -2
  18. data/lib/dry/types/compiler.rb +56 -41
  19. data/lib/dry/types/constrained.rb +81 -32
  20. data/lib/dry/types/constrained/coercible.rb +36 -6
  21. data/lib/dry/types/constraints.rb +18 -4
  22. data/lib/dry/types/constructor.rb +127 -54
  23. data/lib/dry/types/constructor/function.rb +216 -0
  24. data/lib/dry/types/constructor/wrapper.rb +94 -0
  25. data/lib/dry/types/container.rb +7 -0
  26. data/lib/dry/types/core.rb +54 -21
  27. data/lib/dry/types/decorator.rb +38 -17
  28. data/lib/dry/types/default.rb +61 -16
  29. data/lib/dry/types/enum.rb +43 -20
  30. data/lib/dry/types/errors.rb +75 -9
  31. data/lib/dry/types/extensions.rb +7 -1
  32. data/lib/dry/types/extensions/maybe.rb +74 -16
  33. data/lib/dry/types/extensions/monads.rb +29 -0
  34. data/lib/dry/types/fn_container.rb +6 -1
  35. data/lib/dry/types/hash.rb +86 -67
  36. data/lib/dry/types/hash/constructor.rb +33 -0
  37. data/lib/dry/types/inflector.rb +3 -1
  38. data/lib/dry/types/json.rb +18 -16
  39. data/lib/dry/types/lax.rb +75 -0
  40. data/lib/dry/types/map.rb +76 -33
  41. data/lib/dry/types/meta.rb +51 -0
  42. data/lib/dry/types/module.rb +120 -0
  43. data/lib/dry/types/nominal.rb +210 -0
  44. data/lib/dry/types/options.rb +13 -26
  45. data/lib/dry/types/params.rb +39 -25
  46. data/lib/dry/types/predicate_inferrer.rb +238 -0
  47. data/lib/dry/types/predicate_registry.rb +34 -0
  48. data/lib/dry/types/primitive_inferrer.rb +97 -0
  49. data/lib/dry/types/printable.rb +16 -0
  50. data/lib/dry/types/printer.rb +315 -0
  51. data/lib/dry/types/result.rb +29 -3
  52. data/lib/dry/types/schema.rb +408 -0
  53. data/lib/dry/types/schema/key.rb +156 -0
  54. data/lib/dry/types/spec/types.rb +103 -33
  55. data/lib/dry/types/sum.rb +84 -35
  56. data/lib/dry/types/type.rb +49 -0
  57. data/lib/dry/types/version.rb +3 -1
  58. metadata +68 -79
  59. data/.gitignore +0 -10
  60. data/.rspec +0 -2
  61. data/.travis.yml +0 -29
  62. data/.yardopts +0 -5
  63. data/CONTRIBUTING.md +0 -29
  64. data/Gemfile +0 -24
  65. data/Rakefile +0 -20
  66. data/benchmarks/hash_schemas.rb +0 -51
  67. data/lib/dry/types/compat/form_types.rb +0 -27
  68. data/lib/dry/types/compat/int.rb +0 -14
  69. data/lib/dry/types/definition.rb +0 -113
  70. data/lib/dry/types/hash/schema.rb +0 -199
  71. data/lib/dry/types/hash/schema_builder.rb +0 -75
  72. data/lib/dry/types/safe.rb +0 -59
@@ -1,2 +0,0 @@
1
- require 'dry/types/compat/int'
2
- require 'dry/types/compat/form_types'
@@ -1,6 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/deprecations"
4
+
1
5
  module Dry
2
6
  module Types
7
+ # @api private
3
8
  class Compiler
9
+ extend ::Dry::Core::Deprecations[:'dry-types']
10
+
4
11
  attr_reader :registry
5
12
 
6
13
  def initialize(registry)
@@ -13,33 +20,34 @@ module Dry
13
20
 
14
21
  def visit(node)
15
22
  type, body = node
16
- send(:"visit_#{ type }", body)
23
+ send(:"visit_#{type}", body)
17
24
  end
18
25
 
19
26
  def visit_constrained(node)
20
- definition, rule, meta = node
21
- Types::Constrained.new(visit(definition), rule: visit_rule(rule)).meta(meta)
27
+ nominal, rule = node
28
+ type = visit(nominal)
29
+ type.constrained_type.new(type, rule: visit_rule(rule))
22
30
  end
23
31
 
24
32
  def visit_constructor(node)
25
- definition, fn_register_name, meta = node
26
- fn = Dry::Types::FnContainer[fn_register_name]
27
- primitive = visit(definition)
28
- Types::Constructor.new(primitive, meta: meta, fn: fn)
33
+ nominal, fn = node
34
+ primitive = visit(nominal)
35
+ primitive.constructor(compile_fn(fn))
29
36
  end
30
37
 
31
- def visit_safe(node)
32
- ast, meta = node
33
- Types::Safe.new(visit(ast), meta: meta)
38
+ def visit_lax(node)
39
+ Types::Lax.new(visit(node))
34
40
  end
41
+ deprecate(:visit_safe, :visit_lax)
35
42
 
36
- def visit_definition(node)
43
+ def visit_nominal(node)
37
44
  type, meta = node
45
+ nominal_name = "nominal.#{Types.identifier(type)}"
38
46
 
39
- if registry.registered?(type)
40
- registry[type].meta(meta)
47
+ if registry.registered?(nominal_name)
48
+ registry[nominal_name].meta(meta)
41
49
  else
42
- Definition.new(type, meta: meta)
50
+ Nominal.new(type, meta: meta)
43
51
  end
44
52
  end
45
53
 
@@ -55,65 +63,72 @@ module Dry
55
63
  def visit_array(node)
56
64
  member, meta = node
57
65
  member = member.is_a?(Class) ? member : visit(member)
58
- registry['array'].of(member).meta(meta)
66
+ registry["nominal.array"].of(member).meta(meta)
59
67
  end
60
68
 
61
69
  def visit_hash(node)
62
- constructor, schema, meta = node
63
- merge_with('hash', constructor, schema).meta(meta)
70
+ opts, meta = node
71
+ registry["nominal.hash"].with(**opts, meta: meta)
64
72
  end
65
73
 
66
- def visit_hash_schema(node)
67
- schema, meta = node
68
- merge_with_schema('hash', schema).meta(meta)
74
+ def visit_schema(node)
75
+ keys, options, meta = node
76
+ registry["nominal.hash"].schema(keys.map { |key| visit(key) }).with(**options, meta: meta)
69
77
  end
70
78
 
71
79
  def visit_json_hash(node)
72
- schema, meta = node
73
- merge_with('json.hash', :symbolized, schema).meta(meta)
80
+ keys, meta = node
81
+ registry["json.hash"].schema(keys.map { |key| visit(key) }, meta)
74
82
  end
75
83
 
76
84
  def visit_json_array(node)
77
85
  member, meta = node
78
- registry['json.array'].of(visit(member)).meta(meta)
86
+ registry["json.array"].of(visit(member)).meta(meta)
79
87
  end
80
88
 
81
89
  def visit_params_hash(node)
82
- schema, meta = node
83
- merge_with('params.hash', :symbolized, schema).meta(meta)
90
+ keys, meta = node
91
+ registry["params.hash"].schema(keys.map { |key| visit(key) }, meta)
84
92
  end
85
93
 
86
94
  def visit_params_array(node)
87
95
  member, meta = node
88
- registry['params.array'].of(visit(member)).meta(meta)
96
+ registry["params.array"].of(visit(member)).meta(meta)
89
97
  end
90
98
 
91
- def visit_member(node)
92
- name, type = node
93
- { name => visit(type) }
99
+ def visit_key(node)
100
+ name, required, type = node
101
+ Schema::Key.new(visit(type), name, required: required)
94
102
  end
95
103
 
96
104
  def visit_enum(node)
97
- type, mapping, meta = node
98
- Enum.new(visit(type), mapping: mapping, meta: meta)
105
+ type, mapping = node
106
+ Enum.new(visit(type), mapping: mapping)
99
107
  end
100
108
 
101
109
  def visit_map(node)
102
110
  key_type, value_type, meta = node
103
- registry['hash'].map(visit(key_type), visit(value_type)).meta(meta)
111
+ registry["nominal.hash"].map(visit(key_type), visit(value_type)).meta(meta)
104
112
  end
105
113
 
106
- def merge_with(hash_id, constructor, schema)
107
- registry[hash_id].schema(
108
- schema.map { |key| visit(key) }.reduce({}, :update),
109
- constructor
110
- )
114
+ def visit_any(meta)
115
+ registry["any"].meta(meta)
111
116
  end
112
117
 
113
- def merge_with_schema(hash_id, schema)
114
- registry[hash_id].instantiate(
115
- schema.map { |key| visit(key) }.reduce({}, :update)
116
- )
118
+ def compile_fn(fn)
119
+ type, *node = fn
120
+
121
+ case type
122
+ when :id
123
+ Dry::Types::FnContainer[node.fetch(0)]
124
+ when :callable
125
+ node.fetch(0)
126
+ when :method
127
+ target, method = node
128
+ target.method(method)
129
+ else
130
+ raise ArgumentError, "Cannot build callable from #{fn.inspect}"
131
+ end
117
132
  end
118
133
  end
119
134
  end
@@ -1,93 +1,142 @@
1
- require 'dry/types/decorator'
2
- require 'dry/types/constraints'
3
- require 'dry/types/constrained/coercible'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/equalizer"
4
+ require "dry/types/decorator"
5
+ require "dry/types/constraints"
6
+ require "dry/types/constrained/coercible"
4
7
 
5
8
  module Dry
6
9
  module Types
10
+ # Constrained types apply rules to the input
11
+ #
12
+ # @api public
7
13
  class Constrained
8
14
  include Type
9
- include Dry::Equalizer(:type, :options, :rule, :meta)
10
15
  include Decorator
11
16
  include Builder
17
+ include Printable
18
+ include Dry::Equalizer(:type, :rule, inspect: false, immutable: true)
12
19
 
13
20
  # @return [Dry::Logic::Rule]
14
21
  attr_reader :rule
15
22
 
16
23
  # @param [Type] type
24
+ #
17
25
  # @param [Hash] options
18
- def initialize(type, options)
26
+ #
27
+ # @api public
28
+ def initialize(type, **options)
19
29
  super
20
30
  @rule = options.fetch(:rule)
21
31
  end
22
32
 
23
- # @param [Object] input
24
33
  # @return [Object]
25
- # @raise [ConstraintError]
26
- def call(input)
27
- try(input) do |result|
34
+ #
35
+ # @api private
36
+ def call_unsafe(input)
37
+ result = rule.(input)
38
+
39
+ if result.success?
40
+ type.call_unsafe(input)
41
+ else
28
42
  raise ConstraintError.new(result, input)
29
- end.input
43
+ end
44
+ end
45
+
46
+ # @return [Object]
47
+ #
48
+ # @api private
49
+ def call_safe(input, &block)
50
+ if rule[input]
51
+ type.call_safe(input, &block)
52
+ else
53
+ yield
54
+ end
30
55
  end
31
- alias_method :[], :call
32
-
33
- # @param [Object] input
34
- # @param [#call,nil] block
35
- # @yieldparam [Failure] failure
36
- # @yieldreturn [Result]
37
- # @return [Logic::Result, Result]
38
- # @return [Object] if block given and try fails
56
+
57
+ # Safe coercion attempt. It is similar to #call with a
58
+ # block given but returns a Result instance with metadata
59
+ # about errors (if any).
60
+ #
61
+ # @overload try(input)
62
+ # @param [Object] input
63
+ # @return [Logic::Result]
64
+ #
65
+ # @overload try(input)
66
+ # @param [Object] input
67
+ # @yieldparam [Failure] failure
68
+ # @yieldreturn [Object]
69
+ # @return [Object]
70
+ #
71
+ # @api public
39
72
  def try(input, &block)
40
73
  result = rule.(input)
41
74
 
42
75
  if result.success?
43
76
  type.try(input, &block)
44
77
  else
45
- failure = failure(input, result)
46
- block ? yield(failure) : failure
78
+ failure = failure(input, ConstraintError.new(result, input))
79
+ block_given? ? yield(failure) : failure
47
80
  end
48
81
  end
49
82
 
50
- # @param [Object] value
51
- # @return [Boolean]
52
- def valid?(value)
53
- rule.(value).success? && type.valid?(value)
54
- end
55
-
56
83
  # @param [Hash] options
57
84
  # The options hash provided to {Types.Rule} and combined
58
85
  # using {&} with previous {#rule}
86
+ #
59
87
  # @return [Constrained]
88
+ #
60
89
  # @see Dry::Logic::Operators#and
90
+ #
91
+ # @api public
61
92
  def constrained(options)
62
93
  with(rule: rule & Types.Rule(options))
63
94
  end
64
95
 
65
96
  # @return [true]
97
+ #
98
+ # @api public
66
99
  def constrained?
67
100
  true
68
101
  end
69
102
 
70
103
  # @param [Object] value
104
+ #
71
105
  # @return [Boolean]
106
+ #
107
+ # @api public
72
108
  def ===(value)
73
109
  valid?(value)
74
110
  end
75
111
 
76
- # @api public
112
+ # Build lax type. Constraints are not applicable to lax types hence unwrapping
77
113
  #
78
- # @see Definition#to_ast
114
+ # @return [Lax]
115
+ # @api public
116
+ def lax
117
+ type.lax
118
+ end
119
+
120
+ # @see Nominal#to_ast
121
+ # @api public
79
122
  def to_ast(meta: true)
80
- [:constrained, [type.to_ast(meta: meta),
81
- rule.to_ast,
82
- meta ? self.meta : EMPTY_HASH]]
123
+ [:constrained, [type.to_ast(meta: meta), rule.to_ast]]
124
+ end
125
+
126
+ # @api private
127
+ def constructor_type
128
+ type.constructor_type
83
129
  end
84
130
 
85
131
  private
86
132
 
87
133
  # @param [Object] response
134
+ #
88
135
  # @return [Boolean]
136
+ #
137
+ # @api private
89
138
  def decorate?(response)
90
- super || response.kind_of?(Constructor)
139
+ super || response.is_a?(Constructor)
91
140
  end
92
141
  end
93
142
  end
@@ -1,12 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Types
3
5
  class Constrained
6
+ # Common coercion-related API for constrained types
7
+ #
8
+ # @api public
4
9
  class Coercible < Constrained
5
- # @param [Object] input
6
- # @param [#call,nil] block
7
- # @yieldparam [Failure] failure
8
- # @yieldreturn [Result]
9
- # @return [Result,nil]
10
+ # @return [Object]
11
+ #
12
+ # @api private
13
+ def call_unsafe(input)
14
+ coerced = type.call_unsafe(input)
15
+ result = rule.(coerced)
16
+
17
+ if result.success?
18
+ coerced
19
+ else
20
+ raise ConstraintError.new(result, input)
21
+ end
22
+ end
23
+
24
+ # @return [Object]
25
+ #
26
+ # @api private
27
+ def call_safe(input)
28
+ coerced = type.call_safe(input) { return yield }
29
+
30
+ if rule[coerced]
31
+ coerced
32
+ else
33
+ yield(coerced)
34
+ end
35
+ end
36
+
37
+ # @see Dry::Types::Constrained#try
38
+ #
39
+ # @api public
10
40
  def try(input, &block)
11
41
  result = type.try(input)
12
42
 
@@ -16,7 +46,7 @@ module Dry
16
46
  if validation.success?
17
47
  result
18
48
  else
19
- failure = failure(result.input, validation)
49
+ failure = failure(result.input, ConstraintError.new(validation, input))
20
50
  block ? yield(failure) : failure
21
51
  end
22
52
  else
@@ -1,18 +1,32 @@
1
- require 'dry/logic/rule_compiler'
2
- require 'dry/logic/predicates'
3
- require 'dry/logic/rule/predicate'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/logic/rule_compiler"
4
+ require "dry/logic/predicates"
5
+ require "dry/logic/rule/predicate"
4
6
 
5
7
  module Dry
8
+ # Helper methods for constraint types
9
+ #
10
+ # @api public
6
11
  module Types
7
12
  # @param [Hash] options
13
+ #
8
14
  # @return [Dry::Logic::Rule]
15
+ #
16
+ # @api public
9
17
  def self.Rule(options)
10
18
  rule_compiler.(
11
- options.map { |key, val| Logic::Rule::Predicate.new(Logic::Predicates[:"#{key}?"]).curry(val).to_ast }
19
+ options.map { |key, val|
20
+ Logic::Rule::Predicate.build(
21
+ Logic::Predicates[:"#{key}?"]
22
+ ).curry(val).to_ast
23
+ }
12
24
  ).reduce(:and)
13
25
  end
14
26
 
15
27
  # @return [Dry::Logic::RuleCompiler]
28
+ #
29
+ # @api private
16
30
  def self.rule_compiler
17
31
  @rule_compiler ||= Logic::RuleCompiler.new(Logic::Predicates)
18
32
  end
@@ -1,10 +1,18 @@
1
- require 'dry/types/decorator'
2
- require 'dry/types/fn_container'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/equalizer"
4
+ require "dry/types/fn_container"
5
+ require "dry/types/constructor/function"
6
+ require "dry/types/constructor/wrapper"
3
7
 
4
8
  module Dry
5
9
  module Types
6
- class Constructor < Definition
7
- include Dry::Equalizer(:type, :options, :meta)
10
+ # Constructor types apply a function to the input that is supposed to return
11
+ # a new value. Coercion is a common use case for constructor types.
12
+ #
13
+ # @api public
14
+ class Constructor < Nominal
15
+ include Dry::Equalizer(:type, :options, inspect: false, immutable: true)
8
16
 
9
17
  # @return [#call]
10
18
  attr_reader :fn
@@ -12,114 +20,179 @@ module Dry
12
20
  # @return [Type]
13
21
  attr_reader :type
14
22
 
15
- undef :constrained?
23
+ undef :constrained?, :meta, :optional?, :primitive, :default?, :name
16
24
 
17
25
  # @param [Builder, Object] input
18
26
  # @param [Hash] options
19
27
  # @param [#call, nil] block
20
- def self.new(input, options = {}, &block)
21
- type = input.is_a?(Builder) ? input : Definition.new(input)
22
- super(type, options, &block)
28
+ #
29
+ # @api public
30
+ def self.new(input, **options, &block)
31
+ type = input.is_a?(Builder) ? input : Nominal.new(input)
32
+ super(type, **options, fn: Function[options.fetch(:fn, block)])
23
33
  end
24
34
 
25
- # @param [Type] type
35
+ # @param [Builder, Object] input
26
36
  # @param [Hash] options
27
37
  # @param [#call, nil] block
28
- def initialize(type, options = {}, &block)
29
- @type = type
30
- @fn = options.fetch(:fn, block)
31
-
32
- raise ArgumentError, 'Missing constructor block' if fn.nil?
38
+ #
39
+ # @api public
40
+ def self.[](type, fn:, **options)
41
+ function = Function[fn]
33
42
 
34
- super(type, **options, fn: fn)
43
+ if function.wrapper?
44
+ wrapper_type.new(type, fn: function, **options)
45
+ else
46
+ new(type, fn: function, **options)
47
+ end
35
48
  end
36
49
 
37
- # @return [Class]
38
- def primitive
39
- type.primitive
50
+ # @api private
51
+ def self.wrapper_type
52
+ @wrapper_type ||= begin
53
+ if self < Wrapper
54
+ self
55
+ else
56
+ const_set(:Wrapping, ::Class.new(self).include(Wrapper))
57
+ end
58
+ end
40
59
  end
41
60
 
42
- # @return [String]
43
- def name
44
- type.name
61
+ # Instantiate a new constructor type instance
62
+ #
63
+ # @param [Type] type
64
+ # @param [Function] fn
65
+ # @param [Hash] options
66
+ #
67
+ # @api private
68
+ def initialize(type, fn: nil, **options)
69
+ @type = type
70
+ @fn = fn
71
+
72
+ super(type, **options, fn: fn)
45
73
  end
46
74
 
47
- def default?
48
- type.default?
75
+ # @return [Object]
76
+ #
77
+ # @api private
78
+ def call_safe(input)
79
+ coerced = fn.(input) { |output = input| return yield(output) }
80
+ type.call_safe(coerced) { |output = coerced| yield(output) }
49
81
  end
50
82
 
51
- # @param [Object] input
52
83
  # @return [Object]
53
- def call(input)
54
- type[fn[input]]
84
+ #
85
+ # @api private
86
+ def call_unsafe(input)
87
+ type.call_unsafe(fn.(input))
55
88
  end
56
- alias_method :[], :call
57
89
 
58
90
  # @param [Object] input
59
91
  # @param [#call,nil] block
92
+ #
60
93
  # @return [Logic::Result, Types::Result]
61
94
  # @return [Object] if block given and try fails
95
+ #
96
+ # @api public
62
97
  def try(input, &block)
63
- type.try(fn[input], &block)
64
- rescue TypeError, ArgumentError => e
65
- failure(input, e.message)
98
+ value = fn.(input)
99
+ rescue CoercionError => e
100
+ failure = failure(input, e)
101
+ block_given? ? yield(failure) : failure
102
+ else
103
+ type.try(value, &block)
66
104
  end
67
105
 
106
+ # Build a new constructor by appending a block to the coercion function
107
+ #
68
108
  # @param [#call, nil] new_fn
69
109
  # @param [Hash] options
70
110
  # @param [#call, nil] block
111
+ #
71
112
  # @return [Constructor]
113
+ #
114
+ # @api public
72
115
  def constructor(new_fn = nil, **options, &block)
73
- left = new_fn || block
74
- right = fn
75
-
76
- with(options.merge(fn: -> input { left[right[input]] }))
77
- end
116
+ next_fn = Function[new_fn || block]
78
117
 
79
- # @param [Object] value
80
- # @return [Boolean]
81
- def valid?(value)
82
- type.valid?(value)
118
+ if next_fn.wrapper?
119
+ self.class.wrapper_type.new(with(**options), fn: next_fn)
120
+ else
121
+ with(**options, fn: fn >> next_fn)
122
+ end
83
123
  end
84
- alias_method :===, :valid?
124
+ alias_method :append, :constructor
125
+ alias_method :>>, :constructor
85
126
 
86
127
  # @return [Class]
128
+ #
129
+ # @api private
87
130
  def constrained_type
88
131
  Constrained::Coercible
89
132
  end
90
133
 
91
- # @api public
134
+ # @see Nominal#to_ast
92
135
  #
93
- # @see Definition#to_ast
136
+ # @api public
94
137
  def to_ast(meta: true)
95
- [:constructor, [type.to_ast(meta: meta),
96
- register_fn(fn),
97
- meta ? self.meta : EMPTY_HASH]]
138
+ [:constructor, [type.to_ast(meta: meta), fn.to_ast]]
98
139
  end
99
140
 
100
- private
141
+ # Build a new constructor by prepending a block to the coercion function
142
+ #
143
+ # @param [#call, nil] new_fn
144
+ # @param [Hash] options
145
+ # @param [#call, nil] block
146
+ #
147
+ # @return [Constructor]
148
+ #
149
+ # @api public
150
+ def prepend(new_fn = nil, **options, &block)
151
+ with(**options, fn: fn << (new_fn || block))
152
+ end
153
+ alias_method :<<, :prepend
154
+
155
+ # Build a lax type
156
+ #
157
+ # @return [Lax]
158
+ # @api public
159
+ def lax
160
+ Lax.new(constructor_type[type.lax, **options])
161
+ end
101
162
 
102
- def register_fn(fn)
103
- Dry::Types::FnContainer.register(fn)
163
+ # Wrap the type with a proc
164
+ #
165
+ # @return [Proc]
166
+ #
167
+ # @api public
168
+ def to_proc
169
+ proc { |value| self.(value) }
104
170
  end
105
171
 
172
+ private
173
+
106
174
  # @param [Symbol] meth
107
175
  # @param [Boolean] include_private
108
176
  # @return [Boolean]
177
+ #
178
+ # @api private
109
179
  def respond_to_missing?(meth, include_private = false)
110
180
  super || type.respond_to?(meth)
111
181
  end
112
182
 
113
183
  # Delegates missing methods to {#type}
114
- # @param [Symbol] meth
184
+ #
185
+ # @param [Symbol] method
115
186
  # @param [Array] args
116
187
  # @param [#call, nil] block
117
- def method_missing(meth, *args, &block)
118
- if type.respond_to?(meth)
119
- response = type.__send__(meth, *args, &block)
188
+ #
189
+ # @api private
190
+ def method_missing(method, *args, &block)
191
+ if type.respond_to?(method)
192
+ response = type.public_send(method, *args, &block)
120
193
 
121
- if response.kind_of?(Builder)
122
- self.class.new(response, options)
194
+ if response.is_a?(Type) && type.class.equal?(response.class)
195
+ response.constructor_type[response, **options]
123
196
  else
124
197
  response
125
198
  end