error_normalizer 0.1.1 → 0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/Gemfile.lock +14 -1
- data/README.md +67 -1
- data/error_normalizer.gemspec +2 -0
- data/lib/error_normalizer/error.rb +30 -5
- data/lib/error_normalizer/message_parser/english.rb +32 -0
- data/lib/error_normalizer/message_parser.rb +76 -30
- data/lib/error_normalizer/normalizer.rb +17 -3
- data/lib/error_normalizer/schema_path_translator.rb +73 -0
- data/lib/error_normalizer/version.rb +1 -1
- data/lib/error_normalizer.rb +3 -0
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f05b5d39eabbca2f54ec830fff3ba92e575d7d1cd18fb8245a22958213e8d26
|
4
|
+
data.tar.gz: fea06df20e65dea4222593aa9f13c3c6a2254f4d39a5f5764362f96f84243e16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d59e524a3e46879e56b675b94b10434336b1433e3db00298a5b42a011fbe32d6ec3e8f7f1315785ed502732436e5057060afeecc83753864d380416c97ef79e6
|
7
|
+
data.tar.gz: 47e566c3b25befa7d1b22e5f5fde257466b69d6e5f657c5f227dc661fe487a938a801008a83802b372fb945618f1e54ed0060a3fe985e6d8087fa5b0c6c9c5cd
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -8,6 +8,8 @@ GEM
|
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
ast (2.4.0)
|
11
|
+
byebug (10.0.2)
|
12
|
+
coderay (1.1.2)
|
11
13
|
concurrent-ruby (1.0.5)
|
12
14
|
diff-lcs (1.3)
|
13
15
|
dry-configurable (0.7.0)
|
@@ -37,11 +39,20 @@ GEM
|
|
37
39
|
dry-equalizer (~> 0.2)
|
38
40
|
dry-logic (~> 0.4, >= 0.4.0)
|
39
41
|
dry-types (~> 0.13.1)
|
42
|
+
i18n (1.1.1)
|
43
|
+
concurrent-ruby (~> 1.0)
|
40
44
|
jaro_winkler (1.5.1)
|
45
|
+
method_source (0.9.1)
|
41
46
|
parallel (1.12.1)
|
42
47
|
parser (2.5.1.2)
|
43
48
|
ast (~> 2.4.0)
|
44
49
|
powerpack (0.1.2)
|
50
|
+
pry (0.11.3)
|
51
|
+
coderay (~> 1.1.0)
|
52
|
+
method_source (~> 0.9.0)
|
53
|
+
pry-byebug (3.6.0)
|
54
|
+
byebug (~> 10.0)
|
55
|
+
pry (~> 0.10)
|
45
56
|
rainbow (3.0.0)
|
46
57
|
rake (10.4.2)
|
47
58
|
rspec (3.8.0)
|
@@ -75,9 +86,11 @@ DEPENDENCIES
|
|
75
86
|
bundler (~> 1.16)
|
76
87
|
dry-validation (~> 0.12.2)
|
77
88
|
error_normalizer!
|
89
|
+
i18n (~> 1)
|
90
|
+
pry-byebug (~> 3.6)
|
78
91
|
rake (~> 10.0)
|
79
92
|
rspec (~> 3.0)
|
80
93
|
rubocop (= 0.59.2)
|
81
94
|
|
82
95
|
BUNDLED WITH
|
83
|
-
1.
|
96
|
+
1.17.1
|
data/README.md
CHANGED
@@ -28,6 +28,8 @@ Each error object **must have** 4 required fields: `key`, `type`, `message` and
|
|
28
28
|
|
29
29
|
## Usage
|
30
30
|
|
31
|
+
[DOCUMENTATION](https://www.rubydoc.info/gems/error_normalizer/)
|
32
|
+
|
31
33
|
### dry-validation
|
32
34
|
|
33
35
|
GIVEN following [dry-validation](https://dry-rb.org/gems/dry-validation/) schema
|
@@ -138,6 +140,70 @@ You can customize rule name match pattern, type name or turn off this feature co
|
|
138
140
|
config.type_name = 'rule'
|
139
141
|
end
|
140
142
|
|
143
|
+
#### I18n support
|
144
|
+
|
145
|
+
##### Full message translation
|
146
|
+
|
147
|
+
This feature enables to define localization for schema attributes (think of `path` that you get in `payload`), translate it with I18n and concatenate it with the error messages.
|
148
|
+
|
149
|
+
schema = Dry::Validation.Schema do
|
150
|
+
required(:user).schema do
|
151
|
+
required(:favorite_pet).filled(size?: 3..8)
|
152
|
+
required(:vessel).schema do
|
153
|
+
required(:factory).filled(excluded_from?: ['Bilgewater', 'Shipwreck'])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
AND following input
|
159
|
+
|
160
|
+
errors = schema.(user: { favorite_pet: 'Zuckerberg', vessel: { factory: 'Bilgewater' } }).errors
|
161
|
+
#=> {:user=>{:favorite_pet=>["length must be within 3 - 8"], :company=>{:name=>["must not be one of: Bilgewater, Shipwreck"]}}}
|
162
|
+
|
163
|
+
AND following translations loaded in `I18n`
|
164
|
+
|
165
|
+
en:
|
166
|
+
schemas:
|
167
|
+
user:
|
168
|
+
'@': cap
|
169
|
+
favorite_pet: parrot
|
170
|
+
vessel:
|
171
|
+
'@': ship
|
172
|
+
factory: dockyard
|
173
|
+
|
174
|
+
THEN we can convert it to fully translated errors
|
175
|
+
|
176
|
+
ErrorNormalizer.normalize(errors, i18n_messages: true)
|
177
|
+
# [{
|
178
|
+
# :key=>"length_must_be_within",
|
179
|
+
# :message=>"Cap parrot length must be within 3 - 8",
|
180
|
+
# :payload=>{:path=>"user.favorite_pet", :range=>["3", "15"]},
|
181
|
+
# :type=>"params"
|
182
|
+
# }, {
|
183
|
+
# :key=>"must_not_be_one_of",
|
184
|
+
# :message=>"Cap ship dockyard must not be one of: Bilgewater, Shipwreck",
|
185
|
+
# :payload=>{:path=>"user.vessel.factory", :list=>["Bilgewater", "Shipwreck"]},
|
186
|
+
# :type=>"params"
|
187
|
+
# }]
|
188
|
+
|
189
|
+
You can configure this behaviour globally:
|
190
|
+
|
191
|
+
ErrorNormalizer.configure do |config|
|
192
|
+
config.i18n_messages = true
|
193
|
+
end
|
194
|
+
|
195
|
+
For the i18n lookup rules go check [SchemaPathTranslator documentation](https://www.rubydoc.info/gems/error_normalizer/ErrorNormalizer/SchemaPathTranslator).
|
196
|
+
|
197
|
+
##### Non-english error messages
|
198
|
+
|
199
|
+
If you want to support error messages for the other languages you'll need to define and register localized message parser. You can register it in configuration block:
|
200
|
+
|
201
|
+
ErrorNormalizer.configure do |config|
|
202
|
+
config.message_parsers << RussianMessageParser
|
203
|
+
end
|
204
|
+
|
205
|
+
For message parser implementation please check the [documentation](https://www.rubydoc.info/gems/error_normalizer/ErrorNormalizer/MessageParser) and the source code of `ErrorNormalizer::MessageParser::English`.
|
206
|
+
|
141
207
|
### ActiveModel::Validations
|
142
208
|
|
143
209
|
ActiveModel errors aren't fully supported. By that I mean errors will be converted to the single format, however you won't see really unique error `key` or `payload` with additional info.
|
@@ -178,9 +244,9 @@ THEN we can normalize object errors to API error format
|
|
178
244
|
|
179
245
|
## TODO
|
180
246
|
|
181
|
-
- plugin to make full error translation
|
182
247
|
- configure Gitlab CI
|
183
248
|
- parse ActiveModel error mesasges
|
249
|
+
- support array of errors as an input
|
184
250
|
|
185
251
|
## License
|
186
252
|
|
data/error_normalizer.gemspec
CHANGED
@@ -20,9 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
22
|
spec.add_runtime_dependency 'dry-configurable', '~> 0.7.0'
|
23
|
+
spec.add_development_dependency 'i18n', '~> 1'
|
23
24
|
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
25
26
|
spec.add_development_dependency 'dry-validation', '~> 0.12.2'
|
27
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.6'
|
26
28
|
spec.add_development_dependency 'rake', '~> 10.0'
|
27
29
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
30
|
spec.add_development_dependency 'rubocop', '0.59.2'
|
@@ -2,9 +2,14 @@
|
|
2
2
|
|
3
3
|
class ErrorNormalizer
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
5
|
+
# Struct which makes cosmetic normalization on calling
|
6
|
+
# either {Error#to_hash} or {Error#to_json}.
|
7
|
+
#
|
8
|
+
# Translates message with path via i18n if
|
9
|
+
# corresponding options is passed (see {Error#initialize}).
|
10
|
+
#
|
11
|
+
# Provides case equality check ({Error.===})
|
12
|
+
# to support plain Hash structs.
|
8
13
|
#
|
9
14
|
# @example
|
10
15
|
# Error.new('not_plausible', message: "can't recognize your phone", path: 'user.phone')
|
@@ -23,10 +28,11 @@ class ErrorNormalizer
|
|
23
28
|
# puts message #=> 'YEP'
|
24
29
|
#
|
25
30
|
class Error
|
26
|
-
def initialize(error_key, message: nil, type: 'params', **payload)
|
31
|
+
def initialize(error_key, message: nil, type: 'params', i18n_messages: nil, **payload)
|
27
32
|
@key = error_key
|
28
33
|
@message = message
|
29
34
|
@type = type
|
35
|
+
@i18n_messages = i18n_messages
|
30
36
|
@payload = payload
|
31
37
|
end
|
32
38
|
|
@@ -40,11 +46,23 @@ class ErrorNormalizer
|
|
40
46
|
h.key?('key') && h.key?('message') && h.key?('payload') && h.key?('type')
|
41
47
|
end
|
42
48
|
|
49
|
+
# Translate message with path via i18n.
|
50
|
+
# Delegates path translation to {SchemaPathTranslator}.
|
51
|
+
# @return [String]
|
52
|
+
def full_message
|
53
|
+
return message unless @i18n_messages && @type == 'params'
|
54
|
+
|
55
|
+
path = payload[:path]
|
56
|
+
return if path.nil?
|
57
|
+
|
58
|
+
translate_path(path)
|
59
|
+
end
|
60
|
+
|
43
61
|
# @return [Hash] error Hash representation
|
44
62
|
def to_hash
|
45
63
|
{
|
46
64
|
key: @key,
|
47
|
-
message:
|
65
|
+
message: full_message,
|
48
66
|
payload: payload,
|
49
67
|
type: @type
|
50
68
|
}
|
@@ -64,5 +82,12 @@ class ErrorNormalizer
|
|
64
82
|
def payload
|
65
83
|
@payload.delete_if { |_k, v| v.nil? || v.empty? }
|
66
84
|
end
|
85
|
+
|
86
|
+
def translate_path(path)
|
87
|
+
require 'error_normalizer/schema_path_translator' # do not load if not needed
|
88
|
+
|
89
|
+
path_translation = SchemaPathTranslator.new(path).translate
|
90
|
+
"#{path_translation} #{message}"
|
91
|
+
end
|
67
92
|
end
|
68
93
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'error_normalizer/message_parser'
|
4
|
+
|
5
|
+
class ErrorNormalizer
|
6
|
+
class MessageParser
|
7
|
+
#
|
8
|
+
# Parser tailored for dry-validation default error messages.
|
9
|
+
#
|
10
|
+
class English < MessageParser
|
11
|
+
locale :en
|
12
|
+
|
13
|
+
value_matcher :must_not_include, /\A(?<err>must not include) (?<val>.+)/
|
14
|
+
value_matcher :must_be_equal_to, /\A(?<err>must be equal to) (?<val>.+)/
|
15
|
+
value_matcher :must_not_be_equal_to, /\A(?<err>must not be equal to) (?<val>.+)/
|
16
|
+
value_matcher :must_be_greater_than, /\A(?<err>must be greater than) (?<val>\d+)/
|
17
|
+
value_matcher :must_be_greater_than_or_equal_to, /\A(?<err>must be greater than or equal to) (?<val>\d+)/
|
18
|
+
value_matcher :must_include, /\A(?<err>must include) (?<val>.+)/
|
19
|
+
value_matcher :must_be_less_than, /\A(?<err>must be less than) (?<val>\d+)/
|
20
|
+
value_matcher :must_be_less_than_or_equal_to, /\A(?<err>must be less than or equal to) (?<val>\d+)/
|
21
|
+
value_matcher :size_cannot_be_greater_than, /\A(?<err>size cannot be greater than) (?<val>\d+)/
|
22
|
+
value_matcher :size_cannot_be_less_than, /\A(?<err>size cannot be less than) (?<val>\d+)/
|
23
|
+
value_matcher :size_must_be, /\A(?<err>size must be) (?<val>\d+)/
|
24
|
+
value_matcher :length_must_be, /\A(?<err>length must be) (?<val>\d+)/
|
25
|
+
|
26
|
+
list_matcher :must_not_be_one_of, /\A(?<err>must not be one of): (?<val>.+)/
|
27
|
+
list_matcher :must_be_one_of, /\A(?<err>must be one of): (?<val>.+)/
|
28
|
+
list_matcher :size_must_be_within, /\A(?<err>size must be within) (?<val>.+)/
|
29
|
+
list_matcher :length_must_be_within, /\A(?<err>length must be within) (?<val>.+)/
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -2,7 +2,20 @@
|
|
2
2
|
|
3
3
|
class ErrorNormalizer
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# Base implementation of the error message parser.
|
6
|
+
# Message parsers attempt to extract key, message and payload from the given message.
|
7
|
+
# Instances of {MessageParser} can't parse errors on its own because it does not define
|
8
|
+
# any error matchers but it defines all necessary parse logic
|
9
|
+
# since it doesn't depend on the locale.
|
10
|
+
#
|
11
|
+
# You can easily define your own parser by inheriting from {MessageParser}:
|
12
|
+
#
|
13
|
+
# class RussianMessageParser < ErrorNormalizer::MessageParser
|
14
|
+
# locale :ru
|
15
|
+
#
|
16
|
+
# value_matcher :must_be_equal_to, /(?<err>должен быть равным) (?<val>.+)/u
|
17
|
+
# list_matcher :must_be_on_of, /\A(?<err>должен быть одним из): (?<val>.+)/u
|
18
|
+
# end
|
6
19
|
#
|
7
20
|
# ActiveModel ignored for now because we don't plan to use its validations.
|
8
21
|
# In case message isn't recognized we set error to be a simple
|
@@ -13,34 +26,66 @@ class ErrorNormalizer
|
|
13
26
|
# - {https://github.com/svenfuchs/rails-i18n/blob/70b38b/rails/locale/en-US.yml#L111 ActiveModel::Errors}
|
14
27
|
#
|
15
28
|
class MessageParser
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
AlreadyDefinedError = Class.new(StandardError)
|
30
|
+
|
31
|
+
class << self
|
32
|
+
# Get or set parser locale
|
33
|
+
# @return [Symbol]
|
34
|
+
def locale(i18n_locale = nil)
|
35
|
+
return @locale if i18n_locale.nil?
|
36
|
+
|
37
|
+
@locale = i18n_locale.intern
|
38
|
+
end
|
39
|
+
|
40
|
+
# Define message value matcher with a corresponding error key.
|
41
|
+
# Value matchers add a "value" property to the error payload.
|
42
|
+
# @param key [Symbol] set the error key for a given matcher
|
43
|
+
# @param matcher [Regexp] match and extract error and payload via regexp named groups
|
44
|
+
# @return [void]
|
45
|
+
def value_matcher(key, matcher)
|
46
|
+
raise ArgumentError, 'matcher should be a Regexp' unless matcher.is_a?(Regexp)
|
47
|
+
|
48
|
+
key = key.to_s
|
49
|
+
@value_matchers ||= {}
|
50
|
+
|
51
|
+
raise AlreadyDefinedError if @value_matchers.key?(key)
|
52
|
+
|
53
|
+
@value_matchers[key] = matcher
|
54
|
+
end
|
55
|
+
|
56
|
+
# Define message list matcher with a corresponding error key.
|
57
|
+
# List matchers add a "list" or "range" property to the error payload.
|
58
|
+
# @param key [Symbol] set the error key for a given matcher
|
59
|
+
# @param matcher [Regexp] match and extract error and payload via regexp named groups
|
60
|
+
# @return [void]
|
61
|
+
def list_matcher(key, matcher)
|
62
|
+
raise ArgumentError, 'matcher should be a Regexp' unless matcher.is_a?(Regexp)
|
63
|
+
|
64
|
+
key = key.to_s
|
65
|
+
@list_matchers ||= {}
|
66
|
+
|
67
|
+
raise AlreadyDefinedError if @list_matchers.key?(key)
|
68
|
+
|
69
|
+
@list_matchers[key] = matcher
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Hash] value matchers
|
73
|
+
attr_reader :value_matchers
|
74
|
+
|
75
|
+
# @return [Hash] list matchers
|
76
|
+
attr_reader :list_matchers
|
77
|
+
end
|
37
78
|
|
38
79
|
def initialize(message)
|
80
|
+
@locale = self.class.locale
|
39
81
|
@message = message
|
40
82
|
@key = nil
|
41
83
|
@payload = {}
|
42
84
|
end
|
43
85
|
|
86
|
+
# @return [String] parser locale
|
87
|
+
attr_reader :locale
|
88
|
+
|
44
89
|
# Parse error message
|
45
90
|
# @return (see #to_a)
|
46
91
|
def parse
|
@@ -50,7 +95,7 @@ class ErrorNormalizer
|
|
50
95
|
parse_list_message
|
51
96
|
return to_a if @key
|
52
97
|
|
53
|
-
@key =
|
98
|
+
@key = normalize_message(@message)
|
54
99
|
to_a
|
55
100
|
end
|
56
101
|
|
@@ -62,30 +107,31 @@ class ErrorNormalizer
|
|
62
107
|
private
|
63
108
|
|
64
109
|
def parse_value_message
|
65
|
-
|
110
|
+
self.class.value_matchers.each do |(key, matcher)|
|
66
111
|
data = matcher.match(@message)
|
67
112
|
next if data.nil?
|
68
113
|
|
69
|
-
@key =
|
70
|
-
@payload[:value] = data[:val]
|
114
|
+
@key = key
|
115
|
+
@payload[:value] = data[:val] if data.names.include?('val')
|
71
116
|
|
72
117
|
break
|
73
118
|
end
|
74
119
|
end
|
75
120
|
|
76
121
|
def parse_list_message
|
77
|
-
|
122
|
+
self.class.list_matchers.each do |(key, matcher)|
|
78
123
|
data = matcher.match(@message)
|
79
124
|
next if data.nil?
|
80
125
|
|
81
|
-
@key =
|
82
|
-
@payload.merge!(parse_list_payload(data[:val]))
|
126
|
+
@key = key
|
127
|
+
@payload.merge!(parse_list_payload(data[:val])) if data.names.include?('val')
|
83
128
|
|
84
129
|
break
|
85
130
|
end
|
86
131
|
end
|
87
132
|
|
88
|
-
|
133
|
+
# TODO: fine tune for UTF-8 messages
|
134
|
+
def normalize_message(msg)
|
89
135
|
msg.downcase.tr(' ', '_').gsub(/[^a-z0-9_]/, '')
|
90
136
|
end
|
91
137
|
|
@@ -63,6 +63,7 @@ class ErrorNormalizer
|
|
63
63
|
|
64
64
|
private
|
65
65
|
|
66
|
+
# TODO: support arrays of errors as input
|
66
67
|
def normalize_hash(input) # rubocop:disable AbcSize
|
67
68
|
return add_error(input) if input.is_a?(Error)
|
68
69
|
|
@@ -72,7 +73,7 @@ class ErrorNormalizer
|
|
72
73
|
value.each { |msg| add_error(msg, options) }
|
73
74
|
elsif value.is_a?(Hash)
|
74
75
|
ns = namespaced_path(key)
|
75
|
-
Normalizer.new(value, namespace: ns).normalize.errors.each { |e| add_error(e) }
|
76
|
+
Normalizer.new(value, namespace: ns, **@config).normalize.errors.each { |e| add_error(e) }
|
76
77
|
else
|
77
78
|
raise UnsupportedInputTypeError
|
78
79
|
end
|
@@ -86,8 +87,8 @@ class ErrorNormalizer
|
|
86
87
|
end
|
87
88
|
|
88
89
|
def parse_error(err_message, path, options)
|
89
|
-
|
90
|
-
key, msg, payload =
|
90
|
+
options[:i18n_messages] = @config[:i18n_messages] if options[:i18n_messages].nil?
|
91
|
+
key, msg, payload = *pick_message_parser.new(err_message).parse
|
91
92
|
|
92
93
|
Error.new(key, message: msg, path: namespaced_path(path), **payload, **options)
|
93
94
|
end
|
@@ -111,5 +112,18 @@ class ErrorNormalizer
|
|
111
112
|
|
112
113
|
payload.merge!(type: type)
|
113
114
|
end
|
115
|
+
|
116
|
+
def pick_message_parser # rubocop:disable AbcSize
|
117
|
+
find_by_locale = ->(locale) { ->(parser) { parser.locale == locale } }
|
118
|
+
|
119
|
+
msg_parser = @config[:message_parsers].find(&find_by_locale.(I18n.locale))
|
120
|
+
return msg_parser unless msg_parser.nil?
|
121
|
+
|
122
|
+
warn "No message parser with #{I18n.locale} found, falling back to #{I18n.default_locale}"
|
123
|
+
msg_parser = @config[:message_parsers].find(&find_by_locale.(I18n.default_locale))
|
124
|
+
return msg_parser unless msg_parser.nil?
|
125
|
+
|
126
|
+
raise 'No message parser found' if msg_parser.nil?
|
127
|
+
end
|
114
128
|
end
|
115
129
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ErrorNormalizer
|
4
|
+
#
|
5
|
+
# Find I18n locale for the given path.
|
6
|
+
#
|
7
|
+
class SchemaPathTranslator
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
@namespace = 'schemas' # TODO: make it configurable
|
11
|
+
end
|
12
|
+
|
13
|
+
# Take the path and try to translate each part of it.
|
14
|
+
# Given the path: "user.account.status" lookup path (and translation) will looks like:
|
15
|
+
#
|
16
|
+
# schemas.user.@
|
17
|
+
# schemas.user
|
18
|
+
# user.@
|
19
|
+
# user
|
20
|
+
# +
|
21
|
+
# schemas.user.account.@
|
22
|
+
# schemas.user.account
|
23
|
+
# schemas.account.@
|
24
|
+
# schemas.account
|
25
|
+
# account.@
|
26
|
+
# account
|
27
|
+
# +
|
28
|
+
# schemas.user.account.status.@
|
29
|
+
# schemas.user.account.status
|
30
|
+
# schemas.status.@
|
31
|
+
# schemas.tatus
|
32
|
+
# status.@
|
33
|
+
# tatus
|
34
|
+
#
|
35
|
+
# @return [String] translated path
|
36
|
+
#
|
37
|
+
def translate
|
38
|
+
tokens = @path.split('.')
|
39
|
+
|
40
|
+
translated_tokens = []
|
41
|
+
tokens.each.with_index do |token, i|
|
42
|
+
translated_tokens << translate_token(token, i, tokens)
|
43
|
+
end
|
44
|
+
|
45
|
+
translated_tokens.join(' ').capitalize
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def translate_token(token, token_idx, all_tokens)
|
51
|
+
translation = nil
|
52
|
+
full_path = all_tokens[0..token_idx].join('.')
|
53
|
+
|
54
|
+
lookup = build_lookup(token, full_path)
|
55
|
+
lookup.each { |path| break translation = I18n.t(path) if I18n.exists?(path) }
|
56
|
+
|
57
|
+
translation || token
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_lookup(token, full_path)
|
61
|
+
Set.new.tap do |lookup|
|
62
|
+
lookup << "#{@namespace}.#{full_path}.@"
|
63
|
+
lookup << "#{@namespace}.#{full_path}"
|
64
|
+
lookup << "#{@namespace}.#{token}.@"
|
65
|
+
lookup << "#{@namespace}.#{token}"
|
66
|
+
lookup << "#{full_path}.@"
|
67
|
+
lookup << full_path
|
68
|
+
lookup << "#{token}.@"
|
69
|
+
lookup << token
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/error_normalizer.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'dry-configurable'
|
4
4
|
require 'error_normalizer/version'
|
5
5
|
require 'error_normalizer/normalizer'
|
6
|
+
require 'error_normalizer/message_parser/english'
|
6
7
|
|
7
8
|
#
|
8
9
|
# This class provides high-level API to normalize errors to the single format:
|
@@ -22,6 +23,8 @@ class ErrorNormalizer
|
|
22
23
|
setting :infer_type_from_rule_name, true
|
23
24
|
setting :rule_matcher, /_rule\z/
|
24
25
|
setting :type_name, 'rule'
|
26
|
+
setting :i18n_messages, false
|
27
|
+
setting :message_parsers, [ErrorNormalizer::MessageParser::English]
|
25
28
|
|
26
29
|
#
|
27
30
|
# Normalize errors to flat array of structured errors.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: error_normalizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Kondratenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-configurable
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: i18n
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: 0.12.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.6'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,7 +141,9 @@ files:
|
|
113
141
|
- lib/error_normalizer.rb
|
114
142
|
- lib/error_normalizer/error.rb
|
115
143
|
- lib/error_normalizer/message_parser.rb
|
144
|
+
- lib/error_normalizer/message_parser/english.rb
|
116
145
|
- lib/error_normalizer/normalizer.rb
|
146
|
+
- lib/error_normalizer/schema_path_translator.rb
|
117
147
|
- lib/error_normalizer/version.rb
|
118
148
|
homepage: https://gitlab.yalantis.com/public-repo/error_normalizer/
|
119
149
|
licenses:
|