dry-types 0.14.1 → 0.15.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +15 -0
  3. data/.rubocop.yml +43 -0
  4. data/.travis.yml +12 -11
  5. data/CHANGELOG.md +115 -4
  6. data/Gemfile +2 -3
  7. data/benchmarks/hash_schemas.rb +5 -5
  8. data/dry-types.gemspec +1 -1
  9. data/lib/dry/types.rb +67 -45
  10. data/lib/dry/types/any.rb +11 -2
  11. data/lib/dry/types/array.rb +1 -4
  12. data/lib/dry/types/array/member.rb +2 -2
  13. data/lib/dry/types/builder.rb +23 -3
  14. data/lib/dry/types/builder_methods.rb +10 -11
  15. data/lib/dry/types/coercions/params.rb +2 -0
  16. data/lib/dry/types/compat.rb +0 -2
  17. data/lib/dry/types/compiler.rb +25 -33
  18. data/lib/dry/types/constrained.rb +5 -4
  19. data/lib/dry/types/constructor.rb +32 -11
  20. data/lib/dry/types/container.rb +2 -0
  21. data/lib/dry/types/core.rb +22 -12
  22. data/lib/dry/types/default.rb +4 -4
  23. data/lib/dry/types/enum.rb +10 -3
  24. data/lib/dry/types/errors.rb +1 -1
  25. data/lib/dry/types/extensions/maybe.rb +11 -1
  26. data/lib/dry/types/hash.rb +70 -63
  27. data/lib/dry/types/hash/constructor.rb +20 -0
  28. data/lib/dry/types/json.rb +7 -7
  29. data/lib/dry/types/map.rb +6 -1
  30. data/lib/dry/types/module.rb +115 -0
  31. data/lib/dry/types/{definition.rb → nominal.rb} +10 -4
  32. data/lib/dry/types/options.rb +2 -2
  33. data/lib/dry/types/params.rb +11 -11
  34. data/lib/dry/types/printable.rb +12 -0
  35. data/lib/dry/types/printer.rb +309 -0
  36. data/lib/dry/types/result.rb +2 -2
  37. data/lib/dry/types/safe.rb +4 -2
  38. data/lib/dry/types/schema.rb +298 -0
  39. data/lib/dry/types/schema/key.rb +130 -0
  40. data/lib/dry/types/spec/types.rb +12 -4
  41. data/lib/dry/types/sum.rb +14 -15
  42. data/lib/dry/types/version.rb +1 -1
  43. metadata +18 -8
  44. data/lib/dry/types/compat/form_types.rb +0 -27
  45. data/lib/dry/types/compat/int.rb +0 -14
  46. data/lib/dry/types/hash/schema.rb +0 -199
  47. data/lib/dry/types/hash/schema_builder.rb +0 -75
@@ -1,14 +1,16 @@
1
+ require 'dry/core/deprecations'
1
2
  require 'dry/types/builder'
2
3
  require 'dry/types/result'
3
4
  require 'dry/types/options'
4
5
 
5
6
  module Dry
6
7
  module Types
7
- class Definition
8
+ class Nominal
8
9
  include Type
9
10
  include Options
10
11
  include Builder
11
- include Dry::Equalizer(:primitive, :options, :meta)
12
+ include Printable
13
+ include Dry::Equalizer(:primitive, :options, :meta, inspect: false)
12
14
 
13
15
  # @return [Class]
14
16
  attr_reader :primitive
@@ -96,15 +98,19 @@ module Dry
96
98
  alias_method :valid?, :primitive?
97
99
  alias_method :===, :primitive?
98
100
 
99
- # Return AST representation of a type definition
101
+ # Return AST representation of a type nominal
100
102
  #
101
103
  # @api public
102
104
  #
103
105
  # @return [Array]
104
106
  def to_ast(meta: true)
105
- [:definition, [primitive, meta ? self.meta : EMPTY_HASH]]
107
+ [:nominal, [primitive, meta ? self.meta : EMPTY_HASH]]
106
108
  end
107
109
  end
110
+
111
+ extend Dry::Core::Deprecations[:'dry-types']
112
+ Definition = Nominal
113
+ deprecate_constant(:Definition, message: "Nominal")
108
114
  end
109
115
  end
110
116
 
@@ -4,7 +4,7 @@ module Dry
4
4
  # @return [Hash]
5
5
  attr_reader :options
6
6
 
7
- # @see Definition#initialize
7
+ # @see Nominal#initialize
8
8
  def initialize(*args, meta: EMPTY_HASH, **options)
9
9
  @__args__ = args.freeze
10
10
  @options = options.freeze
@@ -13,7 +13,7 @@ module Dry
13
13
 
14
14
  # @param [Hash] new_options
15
15
  # @return [Type]
16
- def with(new_options)
16
+ def with(**new_options)
17
17
  self.class.new(*@__args__, **options, meta: @meta, **new_options)
18
18
  end
19
19
 
@@ -3,27 +3,27 @@ require 'dry/types/coercions/params'
3
3
  module Dry
4
4
  module Types
5
5
  register('params.nil') do
6
- self['nil'].constructor(Coercions::Params.method(:to_nil))
6
+ self['nominal.nil'].constructor(Coercions::Params.method(:to_nil))
7
7
  end
8
8
 
9
9
  register('params.date') do
10
- self['date'].constructor(Coercions::Params.method(:to_date))
10
+ self['nominal.date'].constructor(Coercions::Params.method(:to_date))
11
11
  end
12
12
 
13
13
  register('params.date_time') do
14
- self['date_time'].constructor(Coercions::Params.method(:to_date_time))
14
+ self['nominal.date_time'].constructor(Coercions::Params.method(:to_date_time))
15
15
  end
16
16
 
17
17
  register('params.time') do
18
- self['time'].constructor(Coercions::Params.method(:to_time))
18
+ self['nominal.time'].constructor(Coercions::Params.method(:to_time))
19
19
  end
20
20
 
21
21
  register('params.true') do
22
- self['true'].constructor(Coercions::Params.method(:to_true))
22
+ self['nominal.true'].constructor(Coercions::Params.method(:to_true))
23
23
  end
24
24
 
25
25
  register('params.false') do
26
- self['false'].constructor(Coercions::Params.method(:to_false))
26
+ self['nominal.false'].constructor(Coercions::Params.method(:to_false))
27
27
  end
28
28
 
29
29
  register('params.bool') do
@@ -31,23 +31,23 @@ module Dry
31
31
  end
32
32
 
33
33
  register('params.integer') do
34
- self['integer'].constructor(Coercions::Params.method(:to_int))
34
+ self['nominal.integer'].constructor(Coercions::Params.method(:to_int))
35
35
  end
36
36
 
37
37
  register('params.float') do
38
- self['float'].constructor(Coercions::Params.method(:to_float))
38
+ self['nominal.float'].constructor(Coercions::Params.method(:to_float))
39
39
  end
40
40
 
41
41
  register('params.decimal') do
42
- self['decimal'].constructor(Coercions::Params.method(:to_decimal))
42
+ self['nominal.decimal'].constructor(Coercions::Params.method(:to_decimal))
43
43
  end
44
44
 
45
45
  register('params.array') do
46
- self['array'].constructor(Coercions::Params.method(:to_ary)).safe
46
+ self['nominal.array'].constructor(Coercions::Params.method(:to_ary)).safe
47
47
  end
48
48
 
49
49
  register('params.hash') do
50
- self['hash'].constructor(Coercions::Params.method(:to_hash)).safe
50
+ self['nominal.hash'].constructor(Coercions::Params.method(:to_hash)).safe
51
51
  end
52
52
  end
53
53
  end
@@ -0,0 +1,12 @@
1
+ module Dry
2
+ module Types
3
+ module Printable
4
+ # @return [String]
5
+ # @api public
6
+ def to_s
7
+ PRINTER.(self) { super }
8
+ end
9
+ alias_method :inspect, :to_s
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,309 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # @api private
6
+ class Printer
7
+ MAPPING = {
8
+ Nominal => :visit_nominal,
9
+ Constructor => :visit_constructor,
10
+ Hash::Constructor => :visit_constructor,
11
+ Constrained => :visit_constrained,
12
+ Constrained::Coercible => :visit_constrained,
13
+ Hash => :visit_hash,
14
+ Schema => :visit_schema,
15
+ Schema::Key => :visit_key,
16
+ Map => :visit_map,
17
+ Array => :visit_array,
18
+ Array::Member => :visit_array_member,
19
+ Safe => :visit_safe,
20
+ Enum => :visit_enum,
21
+ Default => :visit_default,
22
+ Default::Callable => :visit_default,
23
+ Sum => :visit_sum,
24
+ Sum::Constrained => :visit_sum,
25
+ Any.class => :visit_any
26
+ }
27
+
28
+ def call(type)
29
+ output = "".dup
30
+ visit(type) { |str| output << str }
31
+ "#<Dry::Types[#{ output }]>"
32
+ end
33
+
34
+ def visit(type, &block)
35
+ print_with = MAPPING.fetch(type.class) do
36
+ if type.is_a?(Type)
37
+ return yield type.inspect
38
+ else
39
+ raise ArgumentError, "Do not know how to print #{ type.class }"
40
+ end
41
+ end
42
+ send(print_with, type, &block)
43
+ end
44
+
45
+ def visit_any(_)
46
+ yield "Any"
47
+ end
48
+
49
+ def visit_array(_)
50
+ yield "Array"
51
+ end
52
+
53
+ def visit_array_member(array)
54
+ visit(array.member) do |type|
55
+ yield "Array<#{ type }>"
56
+ end
57
+ end
58
+
59
+ def visit_constructor(constructor)
60
+ visit(constructor.type) do |type|
61
+ visit_callable(constructor.fn) do |fn|
62
+ options = constructor.options.dup
63
+ options.delete(:fn)
64
+
65
+ visit_options(options, constructor.meta) do |opts|
66
+ yield "Constructor<#{ type } fn=#{ fn }#{ opts }>"
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def visit_constrained(constrained)
73
+ visit(constrained.type) do |type|
74
+ options = constrained.options.dup
75
+ rule = options.delete(:rule)
76
+
77
+ visit_options(options, constrained.meta) do |opts|
78
+ yield "Constrained<#{ type } rule=[#{ rule.to_s }]>"
79
+ end
80
+ end
81
+ end
82
+
83
+ def visit_schema(schema)
84
+ options = schema.options.dup
85
+ size = schema.count
86
+ key_fn_str = ""
87
+ type_fn_str = ""
88
+ strict_str = ""
89
+
90
+ strict_str = "strict " if options.delete(:strict)
91
+
92
+ if key_fn = options.delete(:key_transform_fn)
93
+ visit_callable(key_fn) do |fn|
94
+ key_fn_str = "key_fn=#{ fn } "
95
+ end
96
+ end
97
+
98
+ if type_fn = options.delete(:type_transform_fn)
99
+ visit_callable(type_fn) do |fn|
100
+ type_fn_str = "type_fn=#{ fn } "
101
+ end
102
+ end
103
+
104
+ keys = options.delete(:keys)
105
+
106
+ visit_options(options, schema.meta) do |opts|
107
+ schema_parameters = "#{ key_fn_str }#{ type_fn_str }#{ strict_str }#{ opts }"
108
+
109
+ header = "Schema<#{ schema_parameters }keys={"
110
+
111
+ if size.zero?
112
+ yield "#{ header}}>"
113
+ else
114
+ yield header.dup << keys.map { |key|
115
+ visit(key) { |type| type }
116
+ }.join(" ") << "}>"
117
+ end
118
+ end
119
+ end
120
+
121
+ def visit_map(map)
122
+ visit(map.key_type) do |key|
123
+ visit(map.value_type) do |value|
124
+ options = map.options.dup
125
+ options.delete(:key_type)
126
+ options.delete(:value_type)
127
+
128
+ visit_options(options, map.meta) do |opts|
129
+ yield "Map<#{ key } => #{ value }>"
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def visit_key(key)
136
+ visit(key.type) do |type|
137
+ if key.required?
138
+ yield "#{ key.name }: #{ type }"
139
+ else
140
+ yield "#{ key.name }?: #{ type }"
141
+ end
142
+ end
143
+ end
144
+
145
+ def visit_sum(sum)
146
+ visit_sum_constructors(sum) do |constructors|
147
+ visit_options(sum.options, sum.meta) do |opts|
148
+ yield "Sum<#{ constructors }#{ opts }>"
149
+ end
150
+ end
151
+ end
152
+
153
+ def visit_sum_constructors(sum)
154
+ case sum.left
155
+ when Sum
156
+ visit_sum_constructors(sum.left) do |left|
157
+ case sum.right
158
+ when Sum
159
+ visit_sum_constructors(sum.right) do |right|
160
+ yield "#{ left } | #{ right }"
161
+ end
162
+ else
163
+ visit(sum.right) do |right|
164
+ yield "#{ left } | #{ right }"
165
+ end
166
+ end
167
+ end
168
+ else
169
+ visit(sum.left) do |left|
170
+ case sum.right
171
+ when Sum
172
+ visit_sum_constructors(sum.right) do |right|
173
+ yield "#{ left } | #{ right }"
174
+ end
175
+ else
176
+ visit(sum.right) do |right|
177
+ yield "#{ left } | #{ right }"
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def visit_enum(enum)
185
+ visit(enum.type) do |type|
186
+ options = enum.options.dup
187
+ mapping = options.delete(:mapping)
188
+
189
+ visit_options(options, enum.meta) do |opts|
190
+ if mapping == enum.inverted_mapping
191
+ values = mapping.values.map(&:inspect).join(", ")
192
+ yield "Enum<#{ type } values={#{ values }}#{ opts }>"
193
+ else
194
+ mapping_str = mapping.map { |key, value|
195
+ "#{ key.inspect }=>#{ value.inspect }"
196
+ }.join(", ")
197
+ yield "Enum<#{ type } mapping={#{ mapping_str }}#{ opts }>"
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ def visit_default(default)
204
+ visit(default.type) do |type|
205
+ visit_options(default.options, default.meta) do |opts|
206
+ if default.is_a?(Default::Callable)
207
+ visit_callable(default.value) do |fn|
208
+ yield "Default<#{ type } value_fn=#{ fn }#{ opts }>"
209
+ end
210
+ else
211
+ yield "Default<#{ type } value=#{ default.value.inspect }#{ opts }>"
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ def visit_nominal(type)
218
+ visit_options(type.options, type.meta) do |opts|
219
+ yield "Nominal<#{ type.primitive }#{ opts }>"
220
+ end
221
+ end
222
+
223
+ def visit_safe(safe)
224
+ visit(safe.type) do |type|
225
+ yield "Safe<#{ type }>"
226
+ end
227
+ end
228
+
229
+ def visit_hash(hash)
230
+ options = hash.options.dup
231
+ type_fn_str = ""
232
+
233
+ if type_fn = options.delete(:type_transform_fn)
234
+ visit_callable(type_fn) do |fn|
235
+ type_fn_str = "type_fn=#{ fn }"
236
+ end
237
+ end
238
+
239
+ visit_options(options, hash.meta) do |opts|
240
+ if opts.empty? && type_fn_str.empty?
241
+ yield "Hash"
242
+ else
243
+ yield "Hash<#{ type_fn_str }#{ opts }>"
244
+ end
245
+ end
246
+ end
247
+
248
+ def visit_callable(callable)
249
+ fn = callable.is_a?(String) ? FnContainer[callable] : callable
250
+
251
+ case fn
252
+ when Method
253
+ yield "#{ fn.receiver }.#{ fn.name }"
254
+ when Proc
255
+ path, line = fn.source_location
256
+
257
+ if line && line.zero?
258
+ yield ".#{ path }"
259
+ elsif path
260
+ yield "#{ path.sub(Dir.pwd + "/", EMPTY_STRING) }:#{ line }"
261
+ elsif fn.lambda?
262
+ yield "(lambda)"
263
+ else
264
+ match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(\w+)\)>\z/)
265
+
266
+ if match
267
+ yield ".#{ match[1] }"
268
+ else
269
+ yield "(proc)"
270
+ end
271
+ end
272
+ else
273
+ call = fn.method(:call)
274
+
275
+ if call.owner == fn.class
276
+ yield "#{ fn.class.to_s }#call"
277
+ else
278
+ yield "#{ fn.to_s }.call"
279
+ end
280
+ end
281
+ end
282
+
283
+ def visit_options(options, meta)
284
+ if options.empty? && meta.empty?
285
+ yield ""
286
+ else
287
+ opts = options.empty? ? "" : " options=#{ options.inspect }"
288
+
289
+ if meta.empty?
290
+ yield opts
291
+ else
292
+ values = meta.map do |key, value|
293
+ case key
294
+ when Symbol
295
+ "#{ key }: #{ value.inspect }"
296
+ else
297
+ "#{ key.inspect }=>#{ value.inspect }"
298
+ end
299
+ end
300
+
301
+ yield "#{ opts } meta={#{ values.join(", ") }}"
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ PRINTER = Printer.new.freeze
308
+ end
309
+ end
@@ -3,7 +3,7 @@ require 'dry/equalizer'
3
3
  module Dry
4
4
  module Types
5
5
  class Result
6
- include Dry::Equalizer(:input)
6
+ include Dry::Equalizer(:input, inspect: false)
7
7
 
8
8
  # @return [Object]
9
9
  attr_reader :input
@@ -26,7 +26,7 @@ module Dry
26
26
  end
27
27
 
28
28
  class Failure < Result
29
- include Dry::Equalizer(:input, :error)
29
+ include Dry::Equalizer(:input, :error, inspect: false)
30
30
 
31
31
  # @return [#to_s]
32
32
  attr_reader :error