error_normalizer 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|