dry-types 0.14.1 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +631 -134
  3. data/LICENSE +17 -17
  4. data/README.md +15 -13
  5. data/dry-types.gemspec +27 -30
  6. data/lib/dry/types/any.rb +32 -12
  7. data/lib/dry/types/array/constructor.rb +32 -0
  8. data/lib/dry/types/array/member.rb +75 -16
  9. data/lib/dry/types/array.rb +19 -6
  10. data/lib/dry/types/builder.rb +131 -15
  11. data/lib/dry/types/builder_methods.rb +49 -20
  12. data/lib/dry/types/coercions/json.rb +43 -7
  13. data/lib/dry/types/coercions/params.rb +118 -31
  14. data/lib/dry/types/coercions.rb +76 -22
  15. data/lib/dry/types/compat.rb +0 -2
  16. data/lib/dry/types/compiler.rb +56 -41
  17. data/lib/dry/types/constrained/coercible.rb +36 -6
  18. data/lib/dry/types/constrained.rb +81 -32
  19. data/lib/dry/types/constraints.rb +18 -4
  20. data/lib/dry/types/constructor/function.rb +216 -0
  21. data/lib/dry/types/constructor/wrapper.rb +94 -0
  22. data/lib/dry/types/constructor.rb +126 -56
  23. data/lib/dry/types/container.rb +7 -0
  24. data/lib/dry/types/core.rb +54 -21
  25. data/lib/dry/types/decorator.rb +38 -17
  26. data/lib/dry/types/default.rb +61 -16
  27. data/lib/dry/types/enum.rb +43 -20
  28. data/lib/dry/types/errors.rb +75 -9
  29. data/lib/dry/types/extensions/maybe.rb +74 -16
  30. data/lib/dry/types/extensions/monads.rb +29 -0
  31. data/lib/dry/types/extensions.rb +7 -1
  32. data/lib/dry/types/fn_container.rb +6 -1
  33. data/lib/dry/types/hash/constructor.rb +33 -0
  34. data/lib/dry/types/hash.rb +86 -67
  35. data/lib/dry/types/inflector.rb +3 -1
  36. data/lib/dry/types/json.rb +18 -16
  37. data/lib/dry/types/lax.rb +75 -0
  38. data/lib/dry/types/map.rb +76 -33
  39. data/lib/dry/types/meta.rb +51 -0
  40. data/lib/dry/types/module.rb +120 -0
  41. data/lib/dry/types/nominal.rb +210 -0
  42. data/lib/dry/types/options.rb +13 -26
  43. data/lib/dry/types/params.rb +39 -25
  44. data/lib/dry/types/predicate_inferrer.rb +238 -0
  45. data/lib/dry/types/predicate_registry.rb +34 -0
  46. data/lib/dry/types/primitive_inferrer.rb +97 -0
  47. data/lib/dry/types/printable.rb +16 -0
  48. data/lib/dry/types/printer.rb +315 -0
  49. data/lib/dry/types/result.rb +29 -3
  50. data/lib/dry/types/schema/key.rb +156 -0
  51. data/lib/dry/types/schema.rb +408 -0
  52. data/lib/dry/types/spec/types.rb +103 -33
  53. data/lib/dry/types/sum.rb +84 -35
  54. data/lib/dry/types/type.rb +49 -0
  55. data/lib/dry/types/version.rb +3 -1
  56. data/lib/dry/types.rb +156 -76
  57. data/lib/dry-types.rb +3 -1
  58. metadata +65 -78
  59. data/.gitignore +0 -10
  60. data/.rspec +0 -2
  61. data/.travis.yml +0 -27
  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
  73. data/log/.gitkeep +0 -0
@@ -1,5 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Types
5
+ # Common API for building type objects in a convenient way
6
+ #
7
+ #
8
+ # @api public
3
9
  module BuilderMethods
4
10
  # @api private
5
11
  def included(base)
@@ -8,7 +14,8 @@ module Dry
8
14
  end
9
15
 
10
16
  # Build an array type.
11
- # It is a shortcut for Array.of
17
+ #
18
+ # Shortcut for Array#of.
12
19
  #
13
20
  # @example
14
21
  # Types::Strings = Types.Array(Types::String)
@@ -17,18 +24,16 @@ module Dry
17
24
  #
18
25
  # @return [Dry::Types::Array]
19
26
  def Array(type)
20
- self::Array.of(type)
27
+ Strict(::Array).of(type)
21
28
  end
22
29
 
23
30
  # Build a hash schema
24
31
  #
25
- # @param [Symbol] schema Schema type
26
32
  # @param [Hash{Symbol => Dry::Types::Type}] type_map
27
33
  #
28
34
  # @return [Dry::Types::Array]
29
- # @api public
30
- def Hash(schema, type_map)
31
- self::Hash.public_send(schema, type_map)
35
+ def Hash(type_map)
36
+ Strict(::Hash).schema(type_map)
32
37
  end
33
38
 
34
39
  # Build a type which values are instances of a given class
@@ -42,9 +47,8 @@ module Dry
42
47
  # @param [Class,Module] klass Class or module
43
48
  #
44
49
  # @return [Dry::Types::Type]
45
- # @api public
46
50
  def Instance(klass)
47
- Definition.new(klass).constrained(type: klass)
51
+ Nominal(klass).constrained(type: klass)
48
52
  end
49
53
  alias_method :Strict, :Instance
50
54
 
@@ -54,9 +58,8 @@ module Dry
54
58
  # @param [Object] value
55
59
  #
56
60
  # @return [Dry::Types::Type]
57
- # @api public
58
61
  def Value(value)
59
- Definition.new(value.class).constrained(eql: value)
62
+ Nominal(value.class).constrained(eql: value)
60
63
  end
61
64
 
62
65
  # Build a type with a single value
@@ -65,9 +68,8 @@ module Dry
65
68
  # @param [Object] object
66
69
  #
67
70
  # @return [Dry::Types::Type]
68
- # @api public
69
71
  def Constant(object)
70
- Definition.new(object.class).constrained(is: object)
72
+ Nominal(object.class).constrained(is: object)
71
73
  end
72
74
 
73
75
  # Build a constructor type
@@ -78,19 +80,31 @@ module Dry
78
80
  # @param [#call,nil] block Value constructor
79
81
  #
80
82
  # @return [Dry::Types::Type]
81
- # @api public
82
83
  def Constructor(klass, cons = nil, &block)
83
- Definition.new(klass).constructor(cons || block || klass.method(:new))
84
+ if klass.is_a?(Type)
85
+ if cons || block
86
+ klass.constructor(cons || block)
87
+ else
88
+ klass
89
+ end
90
+ else
91
+ Nominal(klass).constructor(cons || block || klass.method(:new))
92
+ end
84
93
  end
85
94
 
86
- # Build a definition type
95
+ # Build a nominal type
87
96
  #
88
97
  # @param [Class] klass
89
98
  #
90
99
  # @return [Dry::Types::Type]
91
- # @api public
92
- def Definition(klass)
93
- Definition.new(klass)
100
+ def Nominal(klass)
101
+ if klass <= ::Array
102
+ Array.new(klass)
103
+ elsif klass <= ::Hash
104
+ Hash.new(klass)
105
+ else
106
+ Nominal.new(klass)
107
+ end
94
108
  end
95
109
 
96
110
  # Build a map type
@@ -103,9 +117,24 @@ module Dry
103
117
  # @param [Type] value_type Value type
104
118
  #
105
119
  # @return [Dry::Types::Map]
106
- # @api public
107
120
  def Map(key_type, value_type)
108
- Types['hash'].map(key_type, value_type)
121
+ Nominal(::Hash).map(key_type, value_type)
122
+ end
123
+
124
+ # Builds a constrained nominal type accepting any value that
125
+ # responds to given methods
126
+ #
127
+ # @example
128
+ # Types::Callable = Types.Interface(:call)
129
+ # Types::Contact = Types.Interface(:name, :address)
130
+ #
131
+ # @param methods [Array<String, Symbol>] Method names
132
+ #
133
+ # @return [Dry::Types::Contrained]
134
+ def Interface(*methods)
135
+ methods.reduce(Types["nominal.any"]) do |type, method|
136
+ type.constrained(respond_to: method)
137
+ end
109
138
  end
110
139
  end
111
140
  end
@@ -1,19 +1,55 @@
1
- require 'date'
2
- require 'bigdecimal'
3
- require 'bigdecimal/util'
4
- require 'time'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "bigdecimal"
5
+ require "bigdecimal/util"
6
+ require "time"
5
7
 
6
8
  module Dry
7
9
  module Types
8
10
  module Coercions
11
+ # JSON-specific coercions
12
+ #
13
+ # @api public
9
14
  module JSON
10
15
  extend Coercions
11
16
 
17
+ # @param [Object] input
18
+ #
19
+ # @return [nil] if the input is nil
20
+ #
21
+ # @raise CoercionError
22
+ #
23
+ # @api public
24
+ def self.to_nil(input, &_block)
25
+ if input.nil?
26
+ nil
27
+ elsif block_given?
28
+ yield
29
+ else
30
+ raise CoercionError, "#{input.inspect} is not nil"
31
+ end
32
+ end
33
+
12
34
  # @param [#to_d, Object] input
35
+ #
13
36
  # @return [BigDecimal,nil]
14
- def self.to_decimal(input)
15
- return if input.nil?
16
- input.to_d unless empty_str?(input)
37
+ #
38
+ # @raise CoercionError
39
+ #
40
+ # @api public
41
+ def self.to_decimal(input, &_block)
42
+ if input.is_a?(::Float)
43
+ input.to_d
44
+ else
45
+ BigDecimal(input)
46
+ end
47
+ rescue ArgumentError, TypeError
48
+ if block_given?
49
+ yield
50
+ else
51
+ raise CoercionError, "#{input} cannot be coerced to decimal"
52
+ end
17
53
  end
18
54
  end
19
55
  end
@@ -1,78 +1,165 @@
1
- require 'bigdecimal'
2
- require 'bigdecimal/util'
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
3
5
 
4
6
  module Dry
5
7
  module Types
6
8
  module Coercions
9
+ # Params-specific coercions
10
+ #
11
+ # @api public
7
12
  module Params
8
13
  TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
9
14
  FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
10
- BOOLEAN_MAP = ::Hash[TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])].freeze
15
+ BOOLEAN_MAP = ::Hash[
16
+ TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])
17
+ ].merge(true => true, false => false).freeze
11
18
 
12
19
  extend Coercions
13
20
 
21
+ # @param [Object] input
22
+ #
23
+ # @return [nil] if the input is an empty string or nil
24
+ #
25
+ # @raise CoercionError
26
+ #
27
+ # @api public
28
+ def self.to_nil(input, &_block)
29
+ if input.nil? || empty_str?(input)
30
+ nil
31
+ elsif block_given?
32
+ yield
33
+ else
34
+ raise CoercionError, "#{input.inspect} is not nil"
35
+ end
36
+ end
37
+
14
38
  # @param [String, Object] input
39
+ #
15
40
  # @return [Boolean,Object]
41
+ #
16
42
  # @see TRUE_VALUES
17
43
  # @see FALSE_VALUES
18
- def self.to_true(input)
19
- BOOLEAN_MAP.fetch(input.to_s, input)
44
+ #
45
+ # @raise CoercionError
46
+ #
47
+ # @api public
48
+ def self.to_true(input, &_block)
49
+ BOOLEAN_MAP.fetch(input.to_s) do
50
+ if block_given?
51
+ yield
52
+ else
53
+ raise CoercionError, "#{input} cannot be coerced to true"
54
+ end
55
+ end
20
56
  end
21
57
 
22
58
  # @param [String, Object] input
59
+ #
23
60
  # @return [Boolean,Object]
61
+ #
24
62
  # @see TRUE_VALUES
25
63
  # @see FALSE_VALUES
26
- def self.to_false(input)
27
- BOOLEAN_MAP.fetch(input.to_s, input)
64
+ #
65
+ # @raise CoercionError
66
+ #
67
+ # @api public
68
+ def self.to_false(input, &_block)
69
+ BOOLEAN_MAP.fetch(input.to_s) do
70
+ if block_given?
71
+ yield
72
+ else
73
+ raise CoercionError, "#{input} cannot be coerced to false"
74
+ end
75
+ end
28
76
  end
29
77
 
30
78
  # @param [#to_int, #to_i, Object] input
79
+ #
31
80
  # @return [Integer, nil, Object]
32
- def self.to_int(input)
33
- if empty_str?(input)
34
- nil
81
+ #
82
+ # @raise CoercionError
83
+ #
84
+ # @api public
85
+ def self.to_int(input, &block)
86
+ if input.is_a? String
87
+ Integer(input, 10)
35
88
  else
36
89
  Integer(input)
37
90
  end
38
- rescue ArgumentError, TypeError
39
- input
91
+ rescue ArgumentError, TypeError => e
92
+ CoercionError.handle(e, &block)
40
93
  end
41
94
 
42
95
  # @param [#to_f, Object] input
96
+ #
43
97
  # @return [Float, nil, Object]
44
- def self.to_float(input)
45
- if empty_str?(input)
46
- nil
47
- else
48
- Float(input)
49
- end
50
- rescue ArgumentError, TypeError
51
- input
98
+ #
99
+ # @raise CoercionError
100
+ #
101
+ # @api public
102
+ def self.to_float(input, &block)
103
+ Float(input)
104
+ rescue ArgumentError, TypeError => e
105
+ CoercionError.handle(e, &block)
52
106
  end
53
107
 
54
108
  # @param [#to_d, Object] input
109
+ #
55
110
  # @return [BigDecimal, nil, Object]
56
- def self.to_decimal(input)
57
- result = to_float(input)
58
-
59
- if result.instance_of?(Float)
60
- input.to_d
61
- else
62
- result
111
+ #
112
+ # @raise CoercionError
113
+ #
114
+ # @api public
115
+ def self.to_decimal(input, &_block)
116
+ to_float(input) do
117
+ if block_given?
118
+ return yield
119
+ else
120
+ raise CoercionError, "#{input.inspect} cannot be coerced to decimal"
121
+ end
63
122
  end
123
+
124
+ input.to_d
64
125
  end
65
126
 
66
127
  # @param [Array, String, Object] input
128
+ #
67
129
  # @return [Array, Object]
68
- def self.to_ary(input)
69
- empty_str?(input) ? [] : input
130
+ #
131
+ # @raise CoercionError
132
+ #
133
+ # @api public
134
+ def self.to_ary(input, &_block)
135
+ if empty_str?(input)
136
+ []
137
+ elsif input.is_a?(::Array)
138
+ input
139
+ elsif block_given?
140
+ yield
141
+ else
142
+ raise CoercionError, "#{input.inspect} cannot be coerced to array"
143
+ end
70
144
  end
71
145
 
72
146
  # @param [Hash, String, Object] input
147
+ #
73
148
  # @return [Hash, Object]
74
- def self.to_hash(input)
75
- empty_str?(input) ? {} : input
149
+ #
150
+ # @raise CoercionError
151
+ #
152
+ # @api public
153
+ def self.to_hash(input, &_block)
154
+ if empty_str?(input)
155
+ {}
156
+ elsif input.is_a?(::Hash)
157
+ input
158
+ elsif block_given?
159
+ yield
160
+ else
161
+ raise CoercionError, "#{input.inspect} cannot be coerced to hash"
162
+ end
76
163
  end
77
164
  end
78
165
  end
@@ -1,50 +1,104 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Types
5
+ # Common coercion functions used by the built-in `Params` and `JSON` types
6
+ #
7
+ # @api public
3
8
  module Coercions
4
9
  include Dry::Core::Constants
5
10
 
6
- # @param [String, Object] input
7
- # @return [nil] if the input is an empty string
8
- # @return [Object] otherwise the input object is returned
9
- def to_nil(input)
10
- input unless empty_str?(input)
11
- end
12
-
13
11
  # @param [#to_str, Object] input
12
+ #
14
13
  # @return [Date, Object]
14
+ #
15
15
  # @see Date.parse
16
- def to_date(input)
17
- return input unless input.respond_to?(:to_str)
18
- Date.parse(input)
19
- rescue ArgumentError, RangeError
20
- input
16
+ #
17
+ # @api public
18
+ def to_date(input, &block)
19
+ if input.respond_to?(:to_str)
20
+ begin
21
+ ::Date.parse(input)
22
+ rescue ArgumentError, RangeError => e
23
+ CoercionError.handle(e, &block)
24
+ end
25
+ elsif input.is_a?(::Date)
26
+ input
27
+ elsif block_given?
28
+ yield
29
+ else
30
+ raise CoercionError, "#{input.inspect} is not a string"
31
+ end
21
32
  end
22
33
 
23
34
  # @param [#to_str, Object] input
35
+ #
24
36
  # @return [DateTime, Object]
37
+ #
25
38
  # @see DateTime.parse
26
- def to_date_time(input)
27
- return input unless input.respond_to?(:to_str)
28
- DateTime.parse(input)
29
- rescue ArgumentError
30
- input
39
+ #
40
+ # @api public
41
+ def to_date_time(input, &block)
42
+ if input.respond_to?(:to_str)
43
+ begin
44
+ ::DateTime.parse(input)
45
+ rescue ArgumentError => e
46
+ CoercionError.handle(e, &block)
47
+ end
48
+ elsif input.is_a?(::DateTime)
49
+ input
50
+ elsif block_given?
51
+ yield
52
+ else
53
+ raise CoercionError, "#{input.inspect} is not a string"
54
+ end
31
55
  end
32
56
 
33
57
  # @param [#to_str, Object] input
58
+ #
34
59
  # @return [Time, Object]
60
+ #
35
61
  # @see Time.parse
36
- def to_time(input)
37
- return input unless input.respond_to?(:to_str)
38
- Time.parse(input)
39
- rescue ArgumentError
40
- input
62
+ #
63
+ # @api public
64
+ def to_time(input, &block)
65
+ if input.respond_to?(:to_str)
66
+ begin
67
+ ::Time.parse(input)
68
+ rescue ArgumentError => e
69
+ CoercionError.handle(e, &block)
70
+ end
71
+ elsif input.is_a?(::Time)
72
+ input
73
+ elsif block_given?
74
+ yield
75
+ else
76
+ raise CoercionError, "#{input.inspect} is not a string"
77
+ end
78
+ end
79
+
80
+ # @param [#to_sym, Object] input
81
+ #
82
+ # @return [Symbol, Object]
83
+ #
84
+ # @raise CoercionError
85
+ #
86
+ # @api public
87
+ def to_symbol(input, &block)
88
+ input.to_sym
89
+ rescue NoMethodError => e
90
+ CoercionError.handle(e, &block)
41
91
  end
42
92
 
43
93
  private
44
94
 
45
95
  # Checks whether String is empty
96
+ #
46
97
  # @param [String, Object] value
98
+ #
47
99
  # @return [Boolean]
100
+ #
101
+ # @api private
48
102
  def empty_str?(value)
49
103
  EMPTY_STRING.eql?(value)
50
104
  end
@@ -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