dry-types 0.15.0 → 1.0.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 (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