@@ -57,6 +57,8 @@ defmodule Splode do
57
57
"must supply the `unknown_error` option, pointing at a splode error to use in situations where we cannot convert an error."
58
58
)
59
59
60
+ @ merge_with List . wrap ( opts [ :merge_with ] )
61
+
60
62
if Enum . empty? ( opts [ :error_classes ] ) do
61
63
raise ArgumentError ,
62
64
"must supply at least one error class to `use Splode`, via `use Splode, error_classes: [class: ModuleForClass]`"
@@ -180,19 +182,27 @@ defmodule Splode do
180
182
if Keyword . keyword? ( values ) && values != [ ] do
181
183
[ to_error ( values , Keyword . delete ( opts , :bread_crumbs ) ) ]
182
184
else
183
- Enum . map ( values , & to_error ( & 1 , Keyword . delete ( opts , :bread_crumbs ) ) )
185
+ values
186
+ |> flatten_preserving_keywords ( )
187
+ |> Enum . map ( fn error ->
188
+ if Enum . any? ( [ __MODULE__ | @ merge_with ] , & splode_error? ( error , & 1 ) ) do
189
+ error
190
+ else
191
+ to_error ( error , Keyword . delete ( opts , :bread_crumbs ) )
192
+ end
193
+ end )
184
194
end
185
195
186
196
if Enum . count_until ( errors , 2 ) == 1 &&
187
- Enum . at ( errors , 0 ) . class == :special do
197
+ ( Enum . at ( errors , 0 ) . class == :special || Enum . at ( errors , 0 ) . __struct__ . error_class? ( ) ) do
188
198
List . first ( errors )
189
199
else
190
- values
191
- |> flatten_preserving_keywords ( )
200
+ errors
201
+ |> flatten_errors ( )
192
202
|> Enum . uniq_by ( & clear_stacktraces / 1 )
193
203
|> Enum . map ( fn value ->
194
- if splode_error? ( value , __MODULE__ ) do
195
- Map . put ( value , :splode , __MODULE__ )
204
+ if Enum . any? ( [ __MODULE__ | @ merge_with ] , & splode_error? ( value , & 1 ) ) do
205
+ Map . put ( value , :splode , value . splode || __MODULE__ )
196
206
else
197
207
exception_opts =
198
208
if opts [ :stacktrace ] do
@@ -219,16 +229,17 @@ defmodule Splode do
219
229
end
220
230
221
231
defp choose_error ( errors ) do
222
- errors = Enum . map ( errors , & to_error / 1 )
223
-
224
232
[ error | other_errors ] =
225
233
Enum . sort_by ( errors , fn error ->
226
234
# the second element here sorts errors that are already parent errors
227
- { Map . get ( @ error_class_indices , error . class ) ,
235
+ { Map . get ( @ error_class_indices , error . class ) ||
236
+ Map . get ( @ error_class_indices , :unknown ) ,
228
237
@ error_classes [ error . class ] != error . __struct__ }
229
238
end )
230
239
231
- parent_error_module = @ error_classes [ error . class ]
240
+ parent_error_module =
241
+ @ error_classes [ error . class ] || Keyword . get ( @ error_classes , :unknown ) ||
242
+ Splode.Error.Unknown
232
243
233
244
if parent_error_module == error . __struct__ do
234
245
% { error | errors: ( error . errors || [ ] ) ++ other_errors }
@@ -271,16 +282,15 @@ defmodule Splode do
271
282
272
283
def to_error ( other , opts ) do
273
284
cond do
274
- splode_error? ( other , __MODULE__ ) ->
285
+ Enum . any? ( [ __MODULE__ | @ merge_with ] , & splode_error? ( other , & 1 ) ) ->
275
286
other
276
- |> Map . put ( :splode , __MODULE__ )
287
+ |> Map . put ( :splode , other . splode || __MODULE__ )
277
288
|> add_stacktrace ( opts [ :stacktrace ] )
278
289
|> accumulate_bread_crumbs ( opts [ :bread_crumbs ] )
279
290
280
291
is_exception ( other ) ->
281
292
[ error: Exception . format ( :error , other ) , splode: __MODULE__ ]
282
293
|> @ unknown_error . exception ( )
283
- |> Map . put ( :stacktrace , nil )
284
294
|> add_stacktrace ( opts [ :stacktrace ] )
285
295
|> accumulate_bread_crumbs ( opts [ :bread_crumbs ] )
286
296
@@ -293,6 +303,22 @@ defmodule Splode do
293
303
end
294
304
end
295
305
306
+ defp flatten_errors ( errors ) do
307
+ errors
308
+ |> Enum . flat_map ( & List . wrap / 1 )
309
+ |> Enum . flat_map ( fn error ->
310
+ if Enum . any? ( [ __MODULE__ | @ merge_with ] , & splode_error? ( error , & 1 ) ) do
311
+ if error . __struct__ . error_class? ( ) do
312
+ flatten_errors ( error . errors )
313
+ else
314
+ [ error ]
315
+ end
316
+ else
317
+ [ error ]
318
+ end
319
+ end )
320
+ end
321
+
296
322
defp flatten_preserving_keywords ( list ) do
297
323
if Keyword . keyword? ( list ) do
298
324
[ list ]
0 commit comments