error_builder 0.2.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +42 -3
- data/lib/error_builder/engine.rb +6 -9
- data/lib/error_builder/error.rb +23 -2
- data/lib/error_builder/format_resolver.rb +28 -0
- data/lib/error_builder/formats/array.rb +21 -7
- data/lib/error_builder/formats/base.rb +3 -2
- data/lib/error_builder/formats/hash.rb +18 -8
- data/lib/error_builder/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18b518b8436e2ef66d0bb88f820bef052f36df55a4e41bb28324fe0aebe237d8
|
4
|
+
data.tar.gz: 3c2430d0678d632349469410999bb82825ae5e07c1f36e185857222864e59a59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d67f22c74f876da70c19d27267aa4036c796bed1737a18f3ca3da380e446f90705cf5e19a246bba2314bf8c126346545f385102e9a9c325b958205d508c1a3b
|
7
|
+
data.tar.gz: 91deb51af311a62b39edec12ddfc6440e7c02c8f13227d8cc7922ce5c59e0e198b4f728dc1ba085efd1619bdab6df7c107b4fd6173283f09daa4112cda6b570a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.0] - 2025-04-13
|
4
|
+
- Added support of custom format classes.
|
5
|
+
|
6
|
+
## [0.3.0] - 2025-04-06
|
7
|
+
|
8
|
+
- Changed Array and Hash formats.
|
9
|
+
- Added support for nested and flat error structures in both hash and array formats.
|
10
|
+
- Updated documentation and usage examples.
|
11
|
+
- Covered tests.
|
12
|
+
|
13
|
+
## [0.2.0] - 2025-04-05
|
14
|
+
|
15
|
+
- Provide advanced way of error collecting
|
16
|
+
|
3
17
|
## [0.1.0] - 2025-03-30
|
4
18
|
|
5
19
|
- Initial release
|
data/README.md
CHANGED
@@ -34,7 +34,7 @@ If you have to use in Rails:
|
|
34
34
|
3. You can configure the gem by using the ErrorBuilder.configure block:
|
35
35
|
```ruby
|
36
36
|
ErrorBuilder.configure do |config|
|
37
|
-
config.format = :hash # Supported formats: :hash, :array
|
37
|
+
config.format = :hash # Supported formats: :hash, :array, custom class format
|
38
38
|
config.message_format = :string # Supported formats: :string, :array
|
39
39
|
end
|
40
40
|
```
|
@@ -53,7 +53,7 @@ errors.add(:base, "Something went wrong")
|
|
53
53
|
|
54
54
|
3. Convert Errors to Hash or Array (depends on configuration)
|
55
55
|
```ruby
|
56
|
-
errors.to_h #=> {
|
56
|
+
errors.to_h #=> { base: ["Something went wrong"] }
|
57
57
|
```
|
58
58
|
|
59
59
|
### Including in Classes
|
@@ -71,7 +71,46 @@ end
|
|
71
71
|
|
72
72
|
my_service = MyService.new
|
73
73
|
my_service.call
|
74
|
-
my_service.errors.to_h #=> {
|
74
|
+
my_service.errors.to_h #=> { base: ["Something went wrong"] }
|
75
|
+
```
|
76
|
+
|
77
|
+
### Examples
|
78
|
+
|
79
|
+
#### Using nested keys
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class MyService
|
83
|
+
include ErrorBuilder
|
84
|
+
|
85
|
+
def call
|
86
|
+
errors.add("user.locations[0].name", "must be present")
|
87
|
+
|
88
|
+
true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
my_service = MyService.new
|
93
|
+
my_service.call
|
94
|
+
my_service.errors.to_h #=> { "user" => { "locations" => { 0 => { "name" => ["must be present"] } } } } }
|
95
|
+
my_service.errors.to_h(flat: true) #=> { "user.locations[0].name" => ["must be present"] }
|
96
|
+
```
|
97
|
+
|
98
|
+
#### Using custom formats
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
class CustomFormat
|
102
|
+
def initialize(errors, **)
|
103
|
+
@errors = errors
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_h
|
107
|
+
@errors.map { |error| "#{error.key} #{error.message.join(", ")}" }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
errors = ErrorBuilder::Engine.new(format: CustomFormat)
|
112
|
+
errors.add(:base, "Something went wrong")
|
113
|
+
errors.to_h #=> ["base Something went wrong"]
|
75
114
|
```
|
76
115
|
|
77
116
|
## Development
|
data/lib/error_builder/engine.rb
CHANGED
@@ -16,15 +16,12 @@ module ErrorBuilder
|
|
16
16
|
@errors << error
|
17
17
|
end
|
18
18
|
|
19
|
-
def to_h
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
else
|
26
|
-
raise ArgumentError, "Unsupported format: #{format}"
|
27
|
-
end
|
19
|
+
def to_h(flat: false)
|
20
|
+
formatter.new(errors, flat:).to_h
|
21
|
+
end
|
22
|
+
|
23
|
+
def formatter
|
24
|
+
FormatResolver.new(format).formatter
|
28
25
|
end
|
29
26
|
end
|
30
27
|
end
|
data/lib/error_builder/error.rb
CHANGED
@@ -29,9 +29,9 @@ module ErrorBuilder
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def keys
|
32
|
-
[key]
|
32
|
+
return [key] unless key.to_s.include?(".")
|
33
33
|
|
34
|
-
|
34
|
+
deflat_key
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
@@ -46,5 +46,26 @@ module ErrorBuilder
|
|
46
46
|
raise ArgumentError, "Unsupported message format: #{format}"
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
def deflat_key
|
51
|
+
key
|
52
|
+
.to_s
|
53
|
+
.split(".")
|
54
|
+
.flat_map { |part| part.split(/[\[\]]+/) }
|
55
|
+
.reject(&:empty?)
|
56
|
+
.map { |part| parse_part(part) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_part(part)
|
60
|
+
if integer?(part)
|
61
|
+
part.to_i
|
62
|
+
else
|
63
|
+
key.is_a?(String) ? part : part.to_sym
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def integer?(part)
|
68
|
+
part.match?(/\A\d+\z/)
|
69
|
+
end
|
49
70
|
end
|
50
71
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ErrorBuilder
|
4
|
+
class FormatResolver
|
5
|
+
attr_reader :format
|
6
|
+
|
7
|
+
def initialize(format)
|
8
|
+
@format = format
|
9
|
+
end
|
10
|
+
|
11
|
+
def formatter
|
12
|
+
return built_in_formatter unless format.is_a?(Class)
|
13
|
+
|
14
|
+
format
|
15
|
+
end
|
16
|
+
|
17
|
+
def built_in_formatter
|
18
|
+
case format
|
19
|
+
when :array
|
20
|
+
Formats::Array
|
21
|
+
when :hash
|
22
|
+
Formats::Hash
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Unsupported format: #{format}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -4,22 +4,36 @@ module ErrorBuilder
|
|
4
4
|
module Formats
|
5
5
|
class Array < Base
|
6
6
|
def to_h
|
7
|
-
|
8
|
-
|
9
|
-
end
|
7
|
+
errors.each_with_object([]) do |error, array|
|
8
|
+
keys = flat ? [error.key] : error.keys
|
10
9
|
|
11
|
-
|
10
|
+
build_nested_error(array, keys, error.message)
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def build_nested_error(keys, value)
|
16
|
+
def build_nested_error(array, keys, value)
|
17
17
|
key = keys.shift
|
18
18
|
|
19
19
|
if keys.empty?
|
20
|
-
|
20
|
+
array << [key, value]
|
21
|
+
else
|
22
|
+
nested_array = find_or_create_nested_array(array, key)
|
23
|
+
|
24
|
+
build_nested_error(nested_array, keys, value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_or_create_nested_array(array, key)
|
29
|
+
existing = array.find { |e| e.is_a?(::Array) && e.first == key }
|
30
|
+
|
31
|
+
if existing
|
32
|
+
existing[1]
|
21
33
|
else
|
22
|
-
|
34
|
+
new_array = [key, []]
|
35
|
+
array << new_array
|
36
|
+
new_array[1]
|
23
37
|
end
|
24
38
|
end
|
25
39
|
end
|
@@ -4,24 +4,34 @@ module ErrorBuilder
|
|
4
4
|
module Formats
|
5
5
|
class Hash < Base
|
6
6
|
def to_h
|
7
|
-
|
8
|
-
|
9
|
-
end
|
7
|
+
errors.each_with_object({}) do |error, hash|
|
8
|
+
keys = flat ? [error.key] : error.keys
|
10
9
|
|
11
|
-
|
10
|
+
add_nested_key(hash, keys, error.message)
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def
|
16
|
+
def add_nested_key(hash, keys, value)
|
17
17
|
key = keys.shift
|
18
18
|
|
19
19
|
if keys.empty?
|
20
|
-
hash
|
20
|
+
add_message(hash, key, value)
|
21
21
|
else
|
22
|
-
hash[key
|
22
|
+
hash[key] ||= {}
|
23
23
|
|
24
|
-
|
24
|
+
add_nested_key(hash[key], keys, value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_message(hash, key, value)
|
29
|
+
if value.is_a?(::Array)
|
30
|
+
hash[key] ||= []
|
31
|
+
|
32
|
+
hash[key] += value
|
33
|
+
else
|
34
|
+
hash[key] = value
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: error_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mykhailo Marusyk
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-13 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: zeitwerk
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/error_builder/configuration.rb
|
44
44
|
- lib/error_builder/engine.rb
|
45
45
|
- lib/error_builder/error.rb
|
46
|
+
- lib/error_builder/format_resolver.rb
|
46
47
|
- lib/error_builder/formats/array.rb
|
47
48
|
- lib/error_builder/formats/base.rb
|
48
49
|
- lib/error_builder/formats/hash.rb
|
@@ -55,7 +56,7 @@ metadata:
|
|
55
56
|
allowed_push_host: https://rubygems.org
|
56
57
|
homepage_uri: https://github.com/mmarusyk/error_builder
|
57
58
|
source_code_uri: https://github.com/mmarusyk/error_builder
|
58
|
-
changelog_uri: https://github.com/
|
59
|
+
changelog_uri: https://github.com/mmarusyk/error_builder/blob/main/CHANGELOG.md
|
59
60
|
rdoc_options: []
|
60
61
|
require_paths:
|
61
62
|
- lib
|