dry-types 0.15.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +18 -2
  4. data/.travis.yml +4 -5
  5. data/.yardopts +6 -2
  6. data/CHANGELOG.md +69 -1
  7. data/Gemfile +3 -0
  8. data/README.md +2 -1
  9. data/Rakefile +2 -0
  10. data/benchmarks/hash_schemas.rb +2 -0
  11. data/benchmarks/lax_schema.rb +16 -0
  12. data/benchmarks/profile_invalid_input.rb +15 -0
  13. data/benchmarks/profile_lax_schema_valid.rb +16 -0
  14. data/benchmarks/profile_valid_input.rb +15 -0
  15. data/benchmarks/schema_valid_vs_invalid.rb +21 -0
  16. data/benchmarks/setup.rb +17 -0
  17. data/dry-types.gemspec +4 -2
  18. data/lib/dry-types.rb +2 -0
  19. data/lib/dry/types.rb +51 -13
  20. data/lib/dry/types/any.rb +21 -10
  21. data/lib/dry/types/array.rb +11 -1
  22. data/lib/dry/types/array/member.rb +65 -13
  23. data/lib/dry/types/builder.rb +48 -4
  24. data/lib/dry/types/builder_methods.rb +9 -8
  25. data/lib/dry/types/coercions.rb +71 -19
  26. data/lib/dry/types/coercions/json.rb +22 -3
  27. data/lib/dry/types/coercions/params.rb +98 -30
  28. data/lib/dry/types/compiler.rb +35 -12
  29. data/lib/dry/types/constrained.rb +73 -27
  30. data/lib/dry/types/constrained/coercible.rb +36 -6
  31. data/lib/dry/types/constraints.rb +15 -1
  32. data/lib/dry/types/constructor.rb +90 -43
  33. data/lib/dry/types/constructor/function.rb +201 -0
  34. data/lib/dry/types/container.rb +5 -0
  35. data/lib/dry/types/core.rb +7 -5
  36. data/lib/dry/types/decorator.rb +36 -9
  37. data/lib/dry/types/default.rb +48 -16
  38. data/lib/dry/types/enum.rb +30 -16
  39. data/lib/dry/types/errors.rb +73 -7
  40. data/lib/dry/types/extensions.rb +2 -0
  41. data/lib/dry/types/extensions/maybe.rb +43 -4
  42. data/lib/dry/types/fn_container.rb +5 -0
  43. data/lib/dry/types/hash.rb +22 -3
  44. data/lib/dry/types/hash/constructor.rb +13 -0
  45. data/lib/dry/types/inflector.rb +2 -0
  46. data/lib/dry/types/json.rb +4 -6
  47. data/lib/dry/types/{safe.rb → lax.rb} +34 -17
  48. data/lib/dry/types/map.rb +63 -29
  49. data/lib/dry/types/meta.rb +51 -0
  50. data/lib/dry/types/module.rb +7 -2
  51. data/lib/dry/types/nominal.rb +105 -13
  52. data/lib/dry/types/options.rb +12 -25
  53. data/lib/dry/types/params.rb +5 -3
  54. data/lib/dry/types/printable.rb +5 -1
  55. data/lib/dry/types/printer.rb +58 -57
  56. data/lib/dry/types/result.rb +26 -0
  57. data/lib/dry/types/schema.rb +169 -66
  58. data/lib/dry/types/schema/key.rb +34 -39
  59. data/lib/dry/types/spec/types.rb +41 -1
  60. data/lib/dry/types/sum.rb +70 -21
  61. data/lib/dry/types/type.rb +49 -0
  62. data/lib/dry/types/version.rb +3 -1
  63. metadata +14 -12
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Storage for meta-data
6
+ #
7
+ # @api public
8
+ module Meta
9
+ def initialize(*args, meta: EMPTY_HASH, **options)
10
+ super(*args, **options)
11
+ @meta = meta.freeze
12
+ end
13
+
14
+ # @param [Hash] new_options
15
+ #
16
+ # @return [Type]
17
+ #
18
+ # @api public
19
+ def with(options)
20
+ super(meta: @meta, **options)
21
+ end
22
+
23
+ # @overload meta
24
+ # @return [Hash] metadata associated with type
25
+ #
26
+ # @overload meta(data)
27
+ # @param [Hash] new metadata to merge into existing metadata
28
+ # @return [Type] new type with added metadata
29
+ #
30
+ # @api public
31
+ def meta(data = nil)
32
+ if !data
33
+ @meta
34
+ elsif data.empty?
35
+ self
36
+ else
37
+ with(meta: @meta.merge(data))
38
+ end
39
+ end
40
+
41
+ # Resets meta
42
+ #
43
+ # @return [Dry::Types::Type]
44
+ #
45
+ # @api public
46
+ def pristine
47
+ with(meta: EMPTY_HASH)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/deprecations'
2
4
  require 'dry/types/builder_methods'
3
5
 
@@ -6,12 +8,15 @@ module Dry
6
8
  # Export types registered in a container as module constants.
7
9
  # @example
8
10
  # module Types
9
- # include Dry::Types.module(:strict, :coercible, :nominal, default: :strict)
11
+ # include Dry::Types(:strict, :coercible, :nominal, default: :strict)
10
12
  # end
11
- # # Types.constants
13
+ #
14
+ # Types.constants
12
15
  # # => [:Class, :Strict, :Symbol, :Integer, :Float, :String, :Array, :Hash,
13
16
  # # :Decimal, :Nil, :True, :False, :Bool, :Date, :Nominal, :DateTime, :Range,
14
17
  # # :Coercible, :Time]
18
+ #
19
+ # @api public
15
20
  class Module < ::Module
16
21
  def initialize(registry, *args)
17
22
  @registry = registry
@@ -1,13 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/deprecations'
2
4
  require 'dry/types/builder'
3
5
  require 'dry/types/result'
4
6
  require 'dry/types/options'
7
+ require 'dry/types/meta'
5
8
 
6
9
  module Dry
7
10
  module Types
11
+ # Nominal types define a primitive class and do not apply any constructors or constraints
12
+ #
13
+ # Use these types for annotations and the base for building more complex types on top of them.
14
+ #
15
+ # @api public
8
16
  class Nominal
9
17
  include Type
10
18
  include Options
19
+ include Meta
11
20
  include Builder
12
21
  include Printable
13
22
  include Dry::Equalizer(:primitive, :options, :meta, inspect: false)
@@ -16,7 +25,10 @@ module Dry
16
25
  attr_reader :primitive
17
26
 
18
27
  # @param [Class] primitive
28
+ #
19
29
  # @return [Type]
30
+ #
31
+ # @api private
20
32
  def self.[](primitive)
21
33
  if primitive == ::Array
22
34
  Types::Array
@@ -27,8 +39,12 @@ module Dry
27
39
  end
28
40
  end
29
41
 
42
+ ALWAYS = proc { true }
43
+
30
44
  # @param [Type,Class] primitive
31
45
  # @param [Hash] options
46
+ #
47
+ # @api private
32
48
  def initialize(primitive, **options)
33
49
  super
34
50
  @primitive = primitive
@@ -36,76 +52,152 @@ module Dry
36
52
  end
37
53
 
38
54
  # @return [String]
55
+ #
56
+ # @api public
39
57
  def name
40
58
  primitive.name
41
59
  end
42
60
 
43
61
  # @return [false]
62
+ #
63
+ # @api public
44
64
  def default?
45
65
  false
46
66
  end
47
67
 
48
68
  # @return [false]
69
+ #
70
+ # @api public
49
71
  def constrained?
50
72
  false
51
73
  end
52
74
 
53
75
  # @return [false]
76
+ #
77
+ # @api public
54
78
  def optional?
55
79
  false
56
80
  end
57
81
 
58
82
  # @param [BasicObject] input
83
+ #
84
+ # @return [BasicObject]
85
+ #
86
+ # @api private
87
+ def call_unsafe(input)
88
+ input
89
+ end
90
+
91
+ # @param [BasicObject] input
92
+ #
59
93
  # @return [BasicObject]
60
- def call(input)
94
+ #
95
+ # @api private
96
+ def call_safe(input)
61
97
  input
62
98
  end
63
- alias_method :[], :call
64
99
 
65
100
  # @param [Object] input
66
101
  # @param [#call,nil] block
102
+ #
67
103
  # @yieldparam [Failure] failure
68
104
  # @yieldreturn [Result]
105
+ #
69
106
  # @return [Result,Logic::Result] when a block is not provided
70
107
  # @return [nil] otherwise
71
- def try(input, &block)
72
- if valid?(input)
73
- success(input)
74
- else
75
- failure = failure(input, "#{input.inspect} must be an instance of #{primitive}")
76
- block ? yield(failure) : failure
77
- end
108
+ #
109
+ # @api public
110
+ def try(input)
111
+ success(input)
78
112
  end
79
113
 
80
114
  # @param (see Dry::Types::Success#initialize)
115
+ #
81
116
  # @return [Result::Success]
117
+ #
118
+ # @api public
82
119
  def success(input)
83
120
  Result::Success.new(input)
84
121
  end
85
122
 
86
123
  # @param (see Failure#initialize)
124
+ #
87
125
  # @return [Result::Failure]
126
+ #
127
+ # @api public
88
128
  def failure(input, error)
129
+ unless error.is_a?(CoercionError)
130
+ raise ArgumentError, "error must be a CoercionError"
131
+ end
89
132
  Result::Failure.new(input, error)
90
133
  end
91
134
 
92
135
  # Checks whether value is of a #primitive class
136
+ #
93
137
  # @param [Object] value
138
+ #
94
139
  # @return [Boolean]
140
+ #
141
+ # @api public
95
142
  def primitive?(value)
96
143
  value.is_a?(primitive)
97
144
  end
98
- alias_method :valid?, :primitive?
99
- alias_method :===, :primitive?
145
+
146
+ # @api private
147
+ def coerce(input, &_block)
148
+ if primitive?(input)
149
+ input
150
+ elsif block_given?
151
+ yield
152
+ else
153
+ raise CoercionError, "#{input.inspect} must be an instance of #{primitive}"
154
+ end
155
+ end
156
+
157
+ # @api private
158
+ def try_coerce(input)
159
+ result = success(input)
160
+
161
+ coerce(input) do
162
+ result = failure(
163
+ input,
164
+ CoercionError.new("#{input.inspect} must be an instance of #{primitive}")
165
+ )
166
+ end
167
+
168
+ if block_given?
169
+ yield(result)
170
+ else
171
+ result
172
+ end
173
+ end
100
174
 
101
175
  # Return AST representation of a type nominal
102
176
  #
103
- # @api public
104
- #
105
177
  # @return [Array]
178
+ #
179
+ # @api public
106
180
  def to_ast(meta: true)
107
181
  [:nominal, [primitive, meta ? self.meta : EMPTY_HASH]]
108
182
  end
183
+
184
+ # Return self. Nominal types are lax by definition
185
+ #
186
+ # @return [Nominal]
187
+ #
188
+ # @api public
189
+ def lax
190
+ self
191
+ end
192
+
193
+ # Wrap the type with a proc
194
+ #
195
+ # @return [Proc]
196
+ #
197
+ # @api public
198
+ def to_proc
199
+ ALWAYS
200
+ end
109
201
  end
110
202
 
111
203
  extend Dry::Core::Deprecations[:'dry-types']
@@ -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,11 @@ 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))
51
53
  end
52
54
  end
53
55
  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
@@ -16,7 +16,7 @@ module Dry
16
16
  Map => :visit_map,
17
17
  Array => :visit_array,
18
18
  Array::Member => :visit_array_member,
19
- Safe => :visit_safe,
19
+ Lax => :visit_lax,
20
20
  Enum => :visit_enum,
21
21
  Default => :visit_default,
22
22
  Default::Callable => :visit_default,
@@ -28,7 +28,7 @@ module Dry
28
28
  def call(type)
29
29
  output = "".dup
30
30
  visit(type) { |str| output << str }
31
- "#<Dry::Types[#{ output }]>"
31
+ "#<Dry::Types[#{output}]>"
32
32
  end
33
33
 
34
34
  def visit(type, &block)
@@ -36,7 +36,7 @@ module Dry
36
36
  if type.is_a?(Type)
37
37
  return yield type.inspect
38
38
  else
39
- raise ArgumentError, "Do not know how to print #{ type.class }"
39
+ raise ArgumentError, "Do not know how to print #{type.class}"
40
40
  end
41
41
  end
42
42
  send(print_with, type, &block)
@@ -52,18 +52,18 @@ module Dry
52
52
 
53
53
  def visit_array_member(array)
54
54
  visit(array.member) do |type|
55
- yield "Array<#{ type }>"
55
+ yield "Array<#{type}>"
56
56
  end
57
57
  end
58
58
 
59
59
  def visit_constructor(constructor)
60
60
  visit(constructor.type) do |type|
61
- visit_callable(constructor.fn) do |fn|
61
+ visit_callable(constructor.fn.fn) do |fn|
62
62
  options = constructor.options.dup
63
63
  options.delete(:fn)
64
64
 
65
- visit_options(options, constructor.meta) do |opts|
66
- yield "Constructor<#{ type } fn=#{ fn }#{ opts }>"
65
+ visit_options(options) do |opts|
66
+ yield "Constructor<#{type} fn=#{fn}#{opts}>"
67
67
  end
68
68
  end
69
69
  end
@@ -74,8 +74,8 @@ module Dry
74
74
  options = constrained.options.dup
75
75
  rule = options.delete(:rule)
76
76
 
77
- visit_options(options, constrained.meta) do |opts|
78
- yield "Constrained<#{ type } rule=[#{ rule.to_s }]>"
77
+ visit_options(options) do |opts|
78
+ yield "Constrained<#{type} rule=[#{rule}]>"
79
79
  end
80
80
  end
81
81
  end
@@ -83,37 +83,38 @@ module Dry
83
83
  def visit_schema(schema)
84
84
  options = schema.options.dup
85
85
  size = schema.count
86
- key_fn_str = ""
87
- type_fn_str = ""
88
- strict_str = ""
86
+ key_fn_str = ''
87
+ type_fn_str = ''
88
+ strict_str = ''
89
89
 
90
- strict_str = "strict " if options.delete(:strict)
90
+ strict_str = 'strict ' if options.delete(:strict)
91
91
 
92
92
  if key_fn = options.delete(:key_transform_fn)
93
93
  visit_callable(key_fn) do |fn|
94
- key_fn_str = "key_fn=#{ fn } "
94
+ key_fn_str = "key_fn=#{fn} "
95
95
  end
96
96
  end
97
97
 
98
98
  if type_fn = options.delete(:type_transform_fn)
99
99
  visit_callable(type_fn) do |fn|
100
- type_fn_str = "type_fn=#{ fn } "
100
+ type_fn_str = "type_fn=#{fn} "
101
101
  end
102
102
  end
103
103
 
104
104
  keys = options.delete(:keys)
105
105
 
106
106
  visit_options(options, schema.meta) do |opts|
107
- schema_parameters = "#{ key_fn_str }#{ type_fn_str }#{ strict_str }#{ opts }"
107
+ opts = "#{opts[1..-1]} " unless opts.empty?
108
+ schema_parameters = "#{key_fn_str}#{type_fn_str}#{strict_str}#{opts}"
108
109
 
109
- header = "Schema<#{ schema_parameters }keys={"
110
+ header = "Schema<#{schema_parameters}keys={"
110
111
 
111
112
  if size.zero?
112
113
  yield "#{ header}}>"
113
114
  else
114
115
  yield header.dup << keys.map { |key|
115
116
  visit(key) { |type| type }
116
- }.join(" ") << "}>"
117
+ }.join(' ') << '}>'
117
118
  end
118
119
  end
119
120
  end
@@ -125,8 +126,8 @@ module Dry
125
126
  options.delete(:key_type)
126
127
  options.delete(:value_type)
127
128
 
128
- visit_options(options, map.meta) do |opts|
129
- yield "Map<#{ key } => #{ value }>"
129
+ visit_options(options) do |opts|
130
+ yield "Map<#{key} => #{value}>"
130
131
  end
131
132
  end
132
133
  end
@@ -135,9 +136,9 @@ module Dry
135
136
  def visit_key(key)
136
137
  visit(key.type) do |type|
137
138
  if key.required?
138
- yield "#{ key.name }: #{ type }"
139
+ yield "#{key.name}: #{type}"
139
140
  else
140
- yield "#{ key.name }?: #{ type }"
141
+ yield "#{key.name}?: #{type}"
141
142
  end
142
143
  end
143
144
  end
@@ -145,7 +146,7 @@ module Dry
145
146
  def visit_sum(sum)
146
147
  visit_sum_constructors(sum) do |constructors|
147
148
  visit_options(sum.options, sum.meta) do |opts|
148
- yield "Sum<#{ constructors }#{ opts }>"
149
+ yield "Sum<#{constructors}#{opts}>"
149
150
  end
150
151
  end
151
152
  end
@@ -157,11 +158,11 @@ module Dry
157
158
  case sum.right
158
159
  when Sum
159
160
  visit_sum_constructors(sum.right) do |right|
160
- yield "#{ left } | #{ right }"
161
+ yield "#{left} | #{right}"
161
162
  end
162
163
  else
163
164
  visit(sum.right) do |right|
164
- yield "#{ left } | #{ right }"
165
+ yield "#{left} | #{right}"
165
166
  end
166
167
  end
167
168
  end
@@ -170,11 +171,11 @@ module Dry
170
171
  case sum.right
171
172
  when Sum
172
173
  visit_sum_constructors(sum.right) do |right|
173
- yield "#{ left } | #{ right }"
174
+ yield "#{left} | #{right}"
174
175
  end
175
176
  else
176
177
  visit(sum.right) do |right|
177
- yield "#{ left } | #{ right }"
178
+ yield "#{left} | #{right}"
178
179
  end
179
180
  end
180
181
  end
@@ -186,15 +187,15 @@ module Dry
186
187
  options = enum.options.dup
187
188
  mapping = options.delete(:mapping)
188
189
 
189
- visit_options(options, enum.meta) do |opts|
190
+ visit_options(options) do |opts|
190
191
  if mapping == enum.inverted_mapping
191
- values = mapping.values.map(&:inspect).join(", ")
192
- yield "Enum<#{ type } values={#{ values }}#{ opts }>"
192
+ values = mapping.values.map(&:inspect).join(', ')
193
+ yield "Enum<#{type} values={#{values}}#{opts}>"
193
194
  else
194
195
  mapping_str = mapping.map { |key, value|
195
- "#{ key.inspect }=>#{ value.inspect }"
196
- }.join(", ")
197
- yield "Enum<#{ type } mapping={#{ mapping_str }}#{ opts }>"
196
+ "#{ key.inspect }=>#{value.inspect}"
197
+ }.join(', ')
198
+ yield "Enum<#{type} mapping={#{mapping_str}}#{opts}>"
198
199
  end
199
200
  end
200
201
  end
@@ -202,13 +203,13 @@ module Dry
202
203
 
203
204
  def visit_default(default)
204
205
  visit(default.type) do |type|
205
- visit_options(default.options, default.meta) do |opts|
206
+ visit_options(default.options) do |opts|
206
207
  if default.is_a?(Default::Callable)
207
208
  visit_callable(default.value) do |fn|
208
- yield "Default<#{ type } value_fn=#{ fn }#{ opts }>"
209
+ yield "Default<#{type} value_fn=#{fn}#{opts}>"
209
210
  end
210
211
  else
211
- yield "Default<#{ type } value=#{ default.value.inspect }#{ opts }>"
212
+ yield "Default<#{type} value=#{default.value.inspect}#{opts}>"
212
213
  end
213
214
  end
214
215
  end
@@ -216,31 +217,31 @@ module Dry
216
217
 
217
218
  def visit_nominal(type)
218
219
  visit_options(type.options, type.meta) do |opts|
219
- yield "Nominal<#{ type.primitive }#{ opts }>"
220
+ yield "Nominal<#{type.primitive}#{opts}>"
220
221
  end
221
222
  end
222
223
 
223
- def visit_safe(safe)
224
- visit(safe.type) do |type|
225
- yield "Safe<#{ type }>"
224
+ def visit_lax(lax)
225
+ visit(lax.type) do |type|
226
+ yield "Lax<#{type}>"
226
227
  end
227
228
  end
228
229
 
229
230
  def visit_hash(hash)
230
231
  options = hash.options.dup
231
- type_fn_str = ""
232
+ type_fn_str = ''
232
233
 
233
234
  if type_fn = options.delete(:type_transform_fn)
234
235
  visit_callable(type_fn) do |fn|
235
- type_fn_str = "type_fn=#{ fn }"
236
+ type_fn_str = "type_fn=#{fn}"
236
237
  end
237
238
  end
238
239
 
239
240
  visit_options(options, hash.meta) do |opts|
240
241
  if opts.empty? && type_fn_str.empty?
241
- yield "Hash"
242
+ yield 'Hash'
242
243
  else
243
- yield "Hash<#{ type_fn_str }#{ opts }>"
244
+ yield "Hash<#{type_fn_str}#{opts}>"
244
245
  end
245
246
  end
246
247
  end
@@ -255,36 +256,36 @@ module Dry
255
256
  path, line = fn.source_location
256
257
 
257
258
  if line && line.zero?
258
- yield ".#{ path }"
259
+ yield ".#{path}"
259
260
  elsif path
260
- yield "#{ path.sub(Dir.pwd + "/", EMPTY_STRING) }:#{ line }"
261
+ yield "#{path.sub(Dir.pwd + '/', EMPTY_STRING) }:#{line}"
261
262
  elsif fn.lambda?
262
- yield "(lambda)"
263
+ yield '(lambda)'
263
264
  else
264
265
  match = fn.to_s.match(/\A#<Proc:0x\h+\(&:(\w+)\)>\z/)
265
266
 
266
267
  if match
267
- yield ".#{ match[1] }"
268
+ yield ".#{match[1]}"
268
269
  else
269
- yield "(proc)"
270
+ yield '(proc)'
270
271
  end
271
272
  end
272
273
  else
273
274
  call = fn.method(:call)
274
275
 
275
276
  if call.owner == fn.class
276
- yield "#{ fn.class.to_s }#call"
277
+ yield "#{fn.class}#call"
277
278
  else
278
- yield "#{ fn.to_s }.call"
279
+ yield "#{fn}.call"
279
280
  end
280
281
  end
281
282
  end
282
283
 
283
- def visit_options(options, meta)
284
+ def visit_options(options, meta = EMPTY_HASH)
284
285
  if options.empty? && meta.empty?
285
- yield ""
286
+ yield ''
286
287
  else
287
- opts = options.empty? ? "" : " options=#{ options.inspect }"
288
+ opts = options.empty? ? '' : " options=#{options.inspect}"
288
289
 
289
290
  if meta.empty?
290
291
  yield opts
@@ -292,13 +293,13 @@ module Dry
292
293
  values = meta.map do |key, value|
293
294
  case key
294
295
  when Symbol
295
- "#{ key }: #{ value.inspect }"
296
+ "#{key}: #{value.inspect}"
296
297
  else
297
- "#{ key.inspect }=>#{ value.inspect }"
298
+ "#{key.inspect}=>#{value.inspect}"
298
299
  end
299
300
  end
300
301
 
301
- yield "#{ opts } meta={#{ values.join(", ") }}"
302
+ yield "#{opts} meta={#{values.join(', ')}}"
302
303
  end
303
304
  end
304
305
  end