dry-types 0.15.0 → 1.2.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
  3. data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
  4. data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +18 -2
  7. data/.travis.yml +10 -5
  8. data/.yardopts +6 -2
  9. data/CHANGELOG.md +186 -3
  10. data/Gemfile +11 -5
  11. data/README.md +4 -3
  12. data/Rakefile +4 -2
  13. data/benchmarks/hash_schemas.rb +10 -6
  14. data/benchmarks/lax_schema.rb +15 -0
  15. data/benchmarks/profile_invalid_input.rb +15 -0
  16. data/benchmarks/profile_lax_schema_valid.rb +16 -0
  17. data/benchmarks/profile_valid_input.rb +15 -0
  18. data/benchmarks/schema_valid_vs_invalid.rb +21 -0
  19. data/benchmarks/setup.rb +17 -0
  20. data/docsite/source/array-with-member.html.md +13 -0
  21. data/docsite/source/built-in-types.html.md +116 -0
  22. data/docsite/source/constraints.html.md +31 -0
  23. data/docsite/source/custom-types.html.md +93 -0
  24. data/docsite/source/default-values.html.md +91 -0
  25. data/docsite/source/enum.html.md +69 -0
  26. data/docsite/source/getting-started.html.md +57 -0
  27. data/docsite/source/hash-schemas.html.md +169 -0
  28. data/docsite/source/index.html.md +155 -0
  29. data/docsite/source/map.html.md +17 -0
  30. data/docsite/source/optional-values.html.md +96 -0
  31. data/docsite/source/sum.html.md +21 -0
  32. data/dry-types.gemspec +21 -19
  33. data/lib/dry-types.rb +2 -0
  34. data/lib/dry/types.rb +60 -17
  35. data/lib/dry/types/any.rb +21 -10
  36. data/lib/dry/types/array.rb +17 -1
  37. data/lib/dry/types/array/constructor.rb +32 -0
  38. data/lib/dry/types/array/member.rb +72 -13
  39. data/lib/dry/types/builder.rb +49 -5
  40. data/lib/dry/types/builder_methods.rb +43 -16
  41. data/lib/dry/types/coercions.rb +84 -19
  42. data/lib/dry/types/coercions/json.rb +22 -3
  43. data/lib/dry/types/coercions/params.rb +98 -30
  44. data/lib/dry/types/compiler.rb +35 -12
  45. data/lib/dry/types/constrained.rb +78 -27
  46. data/lib/dry/types/constrained/coercible.rb +36 -6
  47. data/lib/dry/types/constraints.rb +15 -1
  48. data/lib/dry/types/constructor.rb +77 -62
  49. data/lib/dry/types/constructor/function.rb +200 -0
  50. data/lib/dry/types/container.rb +5 -0
  51. data/lib/dry/types/core.rb +35 -14
  52. data/lib/dry/types/decorator.rb +37 -10
  53. data/lib/dry/types/default.rb +48 -16
  54. data/lib/dry/types/enum.rb +31 -16
  55. data/lib/dry/types/errors.rb +73 -7
  56. data/lib/dry/types/extensions.rb +6 -0
  57. data/lib/dry/types/extensions/maybe.rb +52 -5
  58. data/lib/dry/types/extensions/monads.rb +29 -0
  59. data/lib/dry/types/fn_container.rb +5 -0
  60. data/lib/dry/types/hash.rb +32 -14
  61. data/lib/dry/types/hash/constructor.rb +16 -3
  62. data/lib/dry/types/inflector.rb +2 -0
  63. data/lib/dry/types/json.rb +7 -5
  64. data/lib/dry/types/{safe.rb → lax.rb} +33 -16
  65. data/lib/dry/types/map.rb +70 -32
  66. data/lib/dry/types/meta.rb +51 -0
  67. data/lib/dry/types/module.rb +10 -5
  68. data/lib/dry/types/nominal.rb +105 -14
  69. data/lib/dry/types/options.rb +12 -25
  70. data/lib/dry/types/params.rb +14 -3
  71. data/lib/dry/types/predicate_inferrer.rb +197 -0
  72. data/lib/dry/types/predicate_registry.rb +34 -0
  73. data/lib/dry/types/primitive_inferrer.rb +97 -0
  74. data/lib/dry/types/printable.rb +5 -1
  75. data/lib/dry/types/printer.rb +70 -64
  76. data/lib/dry/types/result.rb +26 -0
  77. data/lib/dry/types/schema.rb +177 -80
  78. data/lib/dry/types/schema/key.rb +48 -35
  79. data/lib/dry/types/spec/types.rb +43 -6
  80. data/lib/dry/types/sum.rb +70 -21
  81. data/lib/dry/types/type.rb +49 -0
  82. data/lib/dry/types/version.rb +3 -1
  83. metadata +91 -62
@@ -1,42 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Types
5
+ # Common API for types with options
6
+ #
7
+ # @api private
3
8
  module Options
4
9
  # @return [Hash]
5
10
  attr_reader :options
6
11
 
7
12
  # @see Nominal#initialize
8
- def initialize(*args, meta: EMPTY_HASH, **options)
13
+ #
14
+ # @api private
15
+ def initialize(*args, **options)
9
16
  @__args__ = args.freeze
10
17
  @options = options.freeze
11
- @meta = meta.freeze
12
18
  end
13
19
 
14
20
  # @param [Hash] new_options
21
+ #
15
22
  # @return [Type]
16
- def with(**new_options)
17
- self.class.new(*@__args__, **options, meta: @meta, **new_options)
18
- end
19
-
20
- # @overload meta
21
- # @return [Hash] metadata associated with type
22
23
  #
23
- # @overload meta(data)
24
- # @param [Hash] new metadata to merge into existing metadata
25
- # @return [Type] new type with added metadata
26
- def meta(data = nil)
27
- if !data
28
- @meta
29
- elsif data.empty?
30
- self
31
- else
32
- with(meta: @meta.merge(data))
33
- end
34
- end
35
-
36
- # Resets meta
37
- # @return [Dry::Types::Type]
38
- def pristine
39
- with(meta: EMPTY_HASH)
24
+ # @api private
25
+ def with(**new_options)
26
+ self.class.new(*@__args__, **options, **new_options)
40
27
  end
41
28
  end
42
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/types/coercions/params'
2
4
 
3
5
  module Dry
@@ -27,7 +29,7 @@ module Dry
27
29
  end
28
30
 
29
31
  register('params.bool') do
30
- (self['params.true'] | self['params.false']).safe
32
+ self['params.true'] | self['params.false']
31
33
  end
32
34
 
33
35
  register('params.integer') do
@@ -43,11 +45,20 @@ module Dry
43
45
  end
44
46
 
45
47
  register('params.array') do
46
- self['nominal.array'].constructor(Coercions::Params.method(:to_ary)).safe
48
+ self['nominal.array'].constructor(Coercions::Params.method(:to_ary))
47
49
  end
48
50
 
49
51
  register('params.hash') do
50
- self['nominal.hash'].constructor(Coercions::Params.method(:to_hash)).safe
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
+ COERCIBLE.each_key do |name|
60
+ next if name.equal?(:string)
61
+ register("optional.params.#{name}", self['params.nil'] | self["params.#{name}"])
51
62
  end
52
63
  end
53
64
  end
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/cache'
4
+ require 'dry/types/predicate_registry'
5
+
6
+ module Dry
7
+ module Types
8
+ # PredicateInferrer returns the list of predicates used by a type.
9
+ #
10
+ # @api public
11
+ class PredicateInferrer
12
+ extend Core::Cache
13
+
14
+ TYPE_TO_PREDICATE = {
15
+ DateTime => :date_time?,
16
+ FalseClass => :false?,
17
+ Integer => :int?,
18
+ NilClass => :nil?,
19
+ String => :str?,
20
+ TrueClass => :true?,
21
+ BigDecimal => :decimal?
22
+ }.freeze
23
+
24
+ REDUCED_TYPES = {
25
+ [[[:true?], [:false?]]] => %i[bool?]
26
+ }.freeze
27
+
28
+ HASH = %i[hash?].freeze
29
+
30
+ ARRAY = %i[array?].freeze
31
+
32
+ NIL = %i[nil?].freeze
33
+
34
+ # Compiler reduces type AST into a list of predicates
35
+ #
36
+ # @api private
37
+ class Compiler
38
+ # @return [PredicateRegistry]
39
+ # @api private
40
+ attr_reader :registry
41
+
42
+ # @api private
43
+ def initialize(registry)
44
+ @registry = registry
45
+ end
46
+
47
+ # @api private
48
+ def infer_predicate(type)
49
+ [TYPE_TO_PREDICATE.fetch(type) { :"#{type.name.split('::').last.downcase}?" }]
50
+ end
51
+
52
+ # @api private
53
+ def visit(node)
54
+ meth, rest = node
55
+ public_send(:"visit_#{meth}", rest)
56
+ end
57
+
58
+ # @api private
59
+ def visit_nominal(node)
60
+ type = node[0]
61
+ predicate = infer_predicate(type)
62
+
63
+ if registry.key?(predicate[0])
64
+ predicate
65
+ else
66
+ [type?: type]
67
+ end
68
+ end
69
+
70
+ # @api private
71
+ def visit_hash(_)
72
+ HASH
73
+ end
74
+
75
+ # @api private
76
+ def visit_array(_)
77
+ ARRAY
78
+ end
79
+
80
+ # @api private
81
+ def visit_lax(node)
82
+ visit(node)
83
+ end
84
+
85
+ # @api private
86
+ def visit_constructor(node)
87
+ other, * = node
88
+ visit(other)
89
+ end
90
+
91
+ # @api private
92
+ def visit_enum(node)
93
+ other, * = node
94
+ visit(other)
95
+ end
96
+
97
+ # @api private
98
+ def visit_sum(node)
99
+ left_node, right_node, = node
100
+ left = visit(left_node)
101
+ right = visit(right_node)
102
+
103
+ if left.eql?(NIL)
104
+ right
105
+ else
106
+ [[left, right]]
107
+ end
108
+ end
109
+
110
+ # @api private
111
+ def visit_constrained(node)
112
+ other, rules = node
113
+ predicates = visit(rules)
114
+
115
+ if predicates.empty?
116
+ visit(other)
117
+ else
118
+ [*visit(other), *merge_predicates(predicates)]
119
+ end
120
+ end
121
+
122
+ # @api private
123
+ def visit_any(_)
124
+ EMPTY_ARRAY
125
+ end
126
+
127
+ # @api private
128
+ def visit_and(node)
129
+ left, right = node
130
+ visit(left) + visit(right)
131
+ end
132
+
133
+ # @api private
134
+ def visit_predicate(node)
135
+ pred, args = node
136
+
137
+ if pred.equal?(:type?)
138
+ EMPTY_ARRAY
139
+ elsif registry.key?(pred)
140
+ *curried, _ = args
141
+ values = curried.map { |_, v| v }
142
+
143
+ if values.empty?
144
+ [pred]
145
+ else
146
+ [pred => values[0]]
147
+ end
148
+ else
149
+ EMPTY_ARRAY
150
+ end
151
+ end
152
+
153
+ private
154
+
155
+ # @api private
156
+ def merge_predicates(nodes)
157
+ preds, merged = nodes.each_with_object([[], {}]) do |predicate, (ps, h)|
158
+ if predicate.is_a?(::Hash)
159
+ h.update(predicate)
160
+ else
161
+ ps << predicate
162
+ end
163
+ end
164
+
165
+ merged.empty? ? preds : [*preds, merged]
166
+ end
167
+ end
168
+
169
+ # @return [Compiler]
170
+ # @api private
171
+ attr_reader :compiler
172
+
173
+ # @api private
174
+ def initialize(registry = PredicateRegistry.new)
175
+ @compiler = Compiler.new(registry)
176
+ end
177
+
178
+ # Infer predicate identifier from the provided type
179
+ #
180
+ # @param [Type] type
181
+ # @return [Symbol]
182
+ #
183
+ # @api private
184
+ def [](type)
185
+ self.class.fetch_or_store(type) do
186
+ predicates = compiler.visit(type.to_ast)
187
+
188
+ if predicates.is_a?(::Hash)
189
+ predicates
190
+ else
191
+ REDUCED_TYPES[predicates] || predicates
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/logic/predicates'
4
+
5
+ module Dry
6
+ module Types
7
+ # A registry with predicate objects from `Dry::Logic::Predicates`
8
+ #
9
+ # @api private
10
+ class PredicateRegistry
11
+ # @api private
12
+ attr_reader :predicates
13
+
14
+ # @api private
15
+ attr_reader :has_predicate
16
+
17
+ # @api private
18
+ def initialize(predicates = Logic::Predicates)
19
+ @predicates = predicates
20
+ @has_predicate = ::Kernel.instance_method(:respond_to?).bind(@predicates)
21
+ end
22
+
23
+ # @api private
24
+ def [](name)
25
+ predicates[name]
26
+ end
27
+
28
+ # @api private
29
+ def key?(name)
30
+ has_predicate.(name)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/cache'
4
+
5
+ module Dry
6
+ module Types
7
+ # PrimitiveInferrer returns the list of classes matching a type.
8
+ #
9
+ # @api public
10
+ class PrimitiveInferrer
11
+ extend Core::Cache
12
+
13
+ # Compiler reduces type AST into a list of primitives
14
+ #
15
+ # @api private
16
+ class Compiler
17
+ # @api private
18
+ def visit(node)
19
+ meth, rest = node
20
+ public_send(:"visit_#{meth}", rest)
21
+ end
22
+
23
+ # @api private
24
+ def visit_nominal(node)
25
+ type, _ = node
26
+ type
27
+ end
28
+
29
+ # @api private
30
+ def visit_hash(_)
31
+ ::Hash
32
+ end
33
+ alias_method :visit_schema, :visit_hash
34
+
35
+ # @api private
36
+ def visit_array(_)
37
+ ::Array
38
+ end
39
+
40
+ # @api private
41
+ def visit_lax(node)
42
+ visit(node)
43
+ end
44
+
45
+ # @api private
46
+ def visit_constructor(node)
47
+ other, * = node
48
+ visit(other)
49
+ end
50
+
51
+ # @api private
52
+ def visit_enum(node)
53
+ other, * = node
54
+ visit(other)
55
+ end
56
+
57
+ # @api private
58
+ def visit_sum(node)
59
+ left, right = node
60
+
61
+ [visit(left), visit(right)].flatten(1)
62
+ end
63
+
64
+ # @api private
65
+ def visit_constrained(node)
66
+ other, * = node
67
+ visit(other)
68
+ end
69
+
70
+ # @api private
71
+ def visit_any(_)
72
+ ::Object
73
+ end
74
+ end
75
+
76
+ # @return [Compiler]
77
+ # @api private
78
+ attr_reader :compiler
79
+
80
+ # @api private
81
+ def initialize
82
+ @compiler = Compiler.new
83
+ end
84
+
85
+ # Infer primitives from the provided type
86
+ #
87
+ # @return [Array[Class]]
88
+ #
89
+ # @api private
90
+ def [](type)
91
+ self.class.fetch_or_store(type) do
92
+ Array(compiler.visit(type.to_ast)).freeze
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,8 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Types
5
+ # @api private
3
6
  module Printable
4
7
  # @return [String]
5
- # @api public
8
+ #
9
+ # @api private
6
10
  def to_s
7
11
  PRINTER.(self) { super }
8
12
  end
@@ -8,6 +8,7 @@ module Dry
8
8
  Nominal => :visit_nominal,
9
9
  Constructor => :visit_constructor,
10
10
  Hash::Constructor => :visit_constructor,
11
+ Array::Constructor => :visit_constructor,
11
12
  Constrained => :visit_constrained,
12
13
  Constrained::Coercible => :visit_constrained,
13
14
  Hash => :visit_hash,
@@ -16,7 +17,7 @@ module Dry
16
17
  Map => :visit_map,
17
18
  Array => :visit_array,
18
19
  Array::Member => :visit_array_member,
19
- Safe => :visit_safe,
20
+ Lax => :visit_lax,
20
21
  Enum => :visit_enum,
21
22
  Default => :visit_default,
22
23
  Default::Callable => :visit_default,
@@ -26,9 +27,9 @@ module Dry
26
27
  }
27
28
 
28
29
  def call(type)
29
- output = "".dup
30
+ output = ''.dup
30
31
  visit(type) { |str| output << str }
31
- "#<Dry::Types[#{ output }]>"
32
+ "#<Dry::Types[#{output}]>"
32
33
  end
33
34
 
34
35
  def visit(type, &block)
@@ -36,34 +37,38 @@ module Dry
36
37
  if type.is_a?(Type)
37
38
  return yield type.inspect
38
39
  else
39
- raise ArgumentError, "Do not know how to print #{ type.class }"
40
+ raise ArgumentError, "Do not know how to print #{type.class}"
40
41
  end
41
42
  end
42
43
  send(print_with, type, &block)
43
44
  end
44
45
 
45
46
  def visit_any(_)
46
- yield "Any"
47
+ yield 'Any'
47
48
  end
48
49
 
49
- def visit_array(_)
50
- yield "Array"
50
+ def visit_array(type)
51
+ visit_options(EMPTY_HASH, type.meta) do |opts|
52
+ yield "Array#{opts}"
53
+ end
51
54
  end
52
55
 
53
56
  def visit_array_member(array)
54
57
  visit(array.member) do |type|
55
- yield "Array<#{ type }>"
58
+ visit_options(EMPTY_HASH, array.meta) do |opts|
59
+ yield "Array<#{type}#{opts}>"
60
+ end
56
61
  end
57
62
  end
58
63
 
59
64
  def visit_constructor(constructor)
60
65
  visit(constructor.type) do |type|
61
- visit_callable(constructor.fn) do |fn|
66
+ visit_callable(constructor.fn.fn) do |fn|
62
67
  options = constructor.options.dup
63
68
  options.delete(:fn)
64
69
 
65
- visit_options(options, constructor.meta) do |opts|
66
- yield "Constructor<#{ type } fn=#{ fn }#{ opts }>"
70
+ visit_options(options) do |opts|
71
+ yield "Constructor<#{type} fn=#{fn}#{opts}>"
67
72
  end
68
73
  end
69
74
  end
@@ -74,8 +79,8 @@ module Dry
74
79
  options = constrained.options.dup
75
80
  rule = options.delete(:rule)
76
81
 
77
- visit_options(options, constrained.meta) do |opts|
78
- yield "Constrained<#{ type } rule=[#{ rule.to_s }]>"
82
+ visit_options(options) do |_opts|
83
+ yield "Constrained<#{type} rule=[#{rule}]>"
79
84
  end
80
85
  end
81
86
  end
@@ -83,37 +88,38 @@ module Dry
83
88
  def visit_schema(schema)
84
89
  options = schema.options.dup
85
90
  size = schema.count
86
- key_fn_str = ""
87
- type_fn_str = ""
88
- strict_str = ""
91
+ key_fn_str = ''
92
+ type_fn_str = ''
93
+ strict_str = ''
89
94
 
90
- strict_str = "strict " if options.delete(:strict)
95
+ strict_str = 'strict ' if options.delete(:strict)
91
96
 
92
97
  if key_fn = options.delete(:key_transform_fn)
93
98
  visit_callable(key_fn) do |fn|
94
- key_fn_str = "key_fn=#{ fn } "
99
+ key_fn_str = "key_fn=#{fn} "
95
100
  end
96
101
  end
97
102
 
98
103
  if type_fn = options.delete(:type_transform_fn)
99
104
  visit_callable(type_fn) do |fn|
100
- type_fn_str = "type_fn=#{ fn } "
105
+ type_fn_str = "type_fn=#{fn} "
101
106
  end
102
107
  end
103
108
 
104
109
  keys = options.delete(:keys)
105
110
 
106
111
  visit_options(options, schema.meta) do |opts|
107
- schema_parameters = "#{ key_fn_str }#{ type_fn_str }#{ strict_str }#{ opts }"
112
+ opts = "#{opts[1..-1]} " unless opts.empty?
113
+ schema_parameters = "#{key_fn_str}#{type_fn_str}#{strict_str}#{opts}"
108
114
 
109
- header = "Schema<#{ schema_parameters }keys={"
115
+ header = "Schema<#{schema_parameters}keys={"
110
116
 
111
117
  if size.zero?
112
- yield "#{ header}}>"
118
+ yield "#{header}}>"
113
119
  else
114
120
  yield header.dup << keys.map { |key|
115
121
  visit(key) { |type| type }
116
- }.join(" ") << "}>"
122
+ }.join(' ') << '}>'
117
123
  end
118
124
  end
119
125
  end
@@ -125,8 +131,8 @@ module Dry
125
131
  options.delete(:key_type)
126
132
  options.delete(:value_type)
127
133
 
128
- visit_options(options, map.meta) do |opts|
129
- yield "Map<#{ key } => #{ value }>"
134
+ visit_options(options) do |_opts|
135
+ yield "Map<#{key} => #{value}>"
130
136
  end
131
137
  end
132
138
  end
@@ -135,9 +141,9 @@ module Dry
135
141
  def visit_key(key)
136
142
  visit(key.type) do |type|
137
143
  if key.required?
138
- yield "#{ key.name }: #{ type }"
144
+ yield "#{key.name}: #{type}"
139
145
  else
140
- yield "#{ key.name }?: #{ type }"
146
+ yield "#{key.name}?: #{type}"
141
147
  end
142
148
  end
143
149
  end
@@ -145,7 +151,7 @@ module Dry
145
151
  def visit_sum(sum)
146
152
  visit_sum_constructors(sum) do |constructors|
147
153
  visit_options(sum.options, sum.meta) do |opts|
148
- yield "Sum<#{ constructors }#{ opts }>"
154
+ yield "Sum<#{constructors}#{opts}>"
149
155
  end
150
156
  end
151
157
  end
@@ -157,11 +163,11 @@ module Dry
157
163
  case sum.right
158
164
  when Sum
159
165
  visit_sum_constructors(sum.right) do |right|
160
- yield "#{ left } | #{ right }"
166
+ yield "#{left} | #{right}"
161
167
  end
162
168
  else
163
169
  visit(sum.right) do |right|
164
- yield "#{ left } | #{ right }"
170
+ yield "#{left} | #{right}"
165
171
  end
166
172
  end
167
173
  end
@@ -170,11 +176,11 @@ module Dry
170
176
  case sum.right
171
177
  when Sum
172
178
  visit_sum_constructors(sum.right) do |right|
173
- yield "#{ left } | #{ right }"
179
+ yield "#{left} | #{right}"
174
180
  end
175
181
  else
176
182
  visit(sum.right) do |right|
177
- yield "#{ left } | #{ right }"
183
+ yield "#{left} | #{right}"
178
184
  end
179
185
  end
180
186
  end
@@ -186,15 +192,15 @@ module Dry
186
192
  options = enum.options.dup
187
193
  mapping = options.delete(:mapping)
188
194
 
189
- visit_options(options, enum.meta) do |opts|
195
+ visit_options(options) do |opts|
190
196
  if mapping == enum.inverted_mapping
191
- values = mapping.values.map(&:inspect).join(", ")
192
- yield "Enum<#{ type } values={#{ values }}#{ opts }>"
197
+ values = mapping.values.map(&:inspect).join(', ')
198
+ yield "Enum<#{type} values={#{values}}#{opts}>"
193
199
  else
194
200
  mapping_str = mapping.map { |key, value|
195
- "#{ key.inspect }=>#{ value.inspect }"
196
- }.join(", ")
197
- yield "Enum<#{ type } mapping={#{ mapping_str }}#{ opts }>"
201
+ "#{key.inspect}=>#{value.inspect}"
202
+ }.join(', ')
203
+ yield "Enum<#{type} mapping={#{mapping_str}}#{opts}>"
198
204
  end
199
205
  end
200
206
  end
@@ -202,13 +208,13 @@ module Dry
202
208
 
203
209
  def visit_default(default)
204
210
  visit(default.type) do |type|
205
- visit_options(default.options, default.meta) do |opts|
211
+ visit_options(default.options) do |opts|
206
212
  if default.is_a?(Default::Callable)
207
213
  visit_callable(default.value) do |fn|
208
- yield "Default<#{ type } value_fn=#{ fn }#{ opts }>"
214
+ yield "Default<#{type} value_fn=#{fn}#{opts}>"
209
215
  end
210
216
  else
211
- yield "Default<#{ type } value=#{ default.value.inspect }#{ opts }>"
217
+ yield "Default<#{type} value=#{default.value.inspect}#{opts}>"
212
218
  end
213
219
  end
214
220
  end
@@ -216,31 +222,31 @@ module Dry
216
222
 
217
223
  def visit_nominal(type)
218
224
  visit_options(type.options, type.meta) do |opts|
219
- yield "Nominal<#{ type.primitive }#{ opts }>"
225
+ yield "Nominal<#{type.primitive}#{opts}>"
220
226
  end
221
227
  end
222
228
 
223
- def visit_safe(safe)
224
- visit(safe.type) do |type|
225
- yield "Safe<#{ type }>"
229
+ def visit_lax(lax)
230
+ visit(lax.type) do |type|
231
+ yield "Lax<#{type}>"
226
232
  end
227
233
  end
228
234
 
229
235
  def visit_hash(hash)
230
236
  options = hash.options.dup
231
- type_fn_str = ""
237
+ type_fn_str = ''
232
238
 
233
239
  if type_fn = options.delete(:type_transform_fn)
234
240
  visit_callable(type_fn) do |fn|
235
- type_fn_str = "type_fn=#{ fn }"
241
+ type_fn_str = "type_fn=#{fn}"
236
242
  end
237
243
  end
238
244
 
239
245
  visit_options(options, hash.meta) do |opts|
240
246
  if opts.empty? && type_fn_str.empty?
241
- yield "Hash"
247
+ yield 'Hash'
242
248
  else
243
- yield "Hash<#{ type_fn_str }#{ opts }>"
249
+ yield "Hash<#{type_fn_str}#{opts}>"
244
250
  end
245
251
  end
246
252
  end
@@ -250,41 +256,41 @@ module Dry
250
256
 
251
257
  case fn
252
258
  when Method
253
- yield "#{ fn.receiver }.#{ fn.name }"
259
+ yield "#{fn.receiver}.#{fn.name}"
254
260
  when Proc
255
261
  path, line = fn.source_location
256
262
 
257
- if line && line.zero?
258
- yield ".#{ path }"
263
+ if line&.zero?
264
+ yield ".#{path}"
259
265
  elsif path
260
- yield "#{ path.sub(Dir.pwd + "/", EMPTY_STRING) }:#{ line }"
266
+ yield "#{path.sub(Dir.pwd + '/', EMPTY_STRING)}:#{line}"
261
267
  elsif fn.lambda?
262
- yield "(lambda)"
268
+ yield '(lambda)'
263
269
  else
264
270
  match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(\w+)\)>\z/)
265
271
 
266
272
  if match
267
- yield ".#{ match[1] }"
273
+ yield ".#{match[1]}"
268
274
  else
269
- yield "(proc)"
275
+ yield '(proc)'
270
276
  end
271
277
  end
272
278
  else
273
279
  call = fn.method(:call)
274
280
 
275
281
  if call.owner == fn.class
276
- yield "#{ fn.class.to_s }#call"
282
+ yield "#{fn.class}#call"
277
283
  else
278
- yield "#{ fn.to_s }.call"
284
+ yield "#{fn}.call"
279
285
  end
280
286
  end
281
287
  end
282
288
 
283
- def visit_options(options, meta)
289
+ def visit_options(options, meta = EMPTY_HASH)
284
290
  if options.empty? && meta.empty?
285
- yield ""
291
+ yield ''
286
292
  else
287
- opts = options.empty? ? "" : " options=#{ options.inspect }"
293
+ opts = options.empty? ? '' : " options=#{options.inspect}"
288
294
 
289
295
  if meta.empty?
290
296
  yield opts
@@ -292,13 +298,13 @@ module Dry
292
298
  values = meta.map do |key, value|
293
299
  case key
294
300
  when Symbol
295
- "#{ key }: #{ value.inspect }"
301
+ "#{key}: #{value.inspect}"
296
302
  else
297
- "#{ key.inspect }=>#{ value.inspect }"
303
+ "#{key.inspect}=>#{value.inspect}"
298
304
  end
299
305
  end
300
306
 
301
- yield "#{ opts } meta={#{ values.join(", ") }}"
307
+ yield "#{opts} meta={#{values.join(', ')}}"
302
308
  end
303
309
  end
304
310
  end