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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4035feeceb8c759e702989ff2d013b40a935fcf4b4ca2afe79b9742738ff39a6
4
- data.tar.gz: f7235ca637c3503f126ff091724d80d672462b08b6b7ade550bba1ad4ab801ef
3
+ metadata.gz: 6f05b5d39eabbca2f54ec830fff3ba92e575d7d1cd18fb8245a22958213e8d26
4
+ data.tar.gz: fea06df20e65dea4222593aa9f13c3c6a2254f4d39a5f5764362f96f84243e16
5
5
  SHA512:
6
- metadata.gz: 252e4a3d03e3c1a1f190c77774fa0ca2ac23adb6ca5bd02afc93a9e7cc4fbe819c63fee1c98c6fee7d9d0a4a485032773a2b56f935b16b8c7d958a17bb9cc7da
7
- data.tar.gz: e50077ea3edd89c7c091aa92138f54fd49bc41ac1f0670fbed866c829e63f7094be1b646613f058ff6ea1775713564af7fec106f0c84b85f4a2083dac6dd0e4e
6
+ metadata.gz: d59e524a3e46879e56b675b94b10434336b1433e3db00298a5b42a011fbe32d6ec3e8f7f1315785ed502732436e5057060afeecc83753864d380416c97ef79e6
7
+ data.tar.gz: 47e566c3b25befa7d1b22e5f5fde257466b69d6e5f657c5f227dc661fe487a938a801008a83802b372fb945618f1e54ed0060a3fe985e6d8087fa5b0c6c9c5cd
data/.rubocop.yml CHANGED
@@ -20,6 +20,9 @@ Style/FrozenStringLiteralComment:
20
20
  Style/ModuleFunction:
21
21
  Enabled: false
22
22
 
23
+ Style/LambdaCall:
24
+ Enabled: false
25
+
23
26
  #################### Naming ##########################
24
27
 
25
28
  Naming/AccessorMethodName:
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.16.6
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
 
@@ -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
- # Error struct which makes cosmetic normalization
6
- # upon calling either {Error#to_hash} or {Error#to_json}.
7
- # Provides case equality check {Error.===} to support plain Hash structs.
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: 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
- # Parse error messages and extract payload metadata.
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
- VALUE_MATCHERS = [
17
- /\A(?<err>must not include) (?<val>.+)/,
18
- /\A(?<err>must be equal to) (?<val>.+)/,
19
- /\A(?<err>must not be equal to) (?<val>.+)/,
20
- /\A(?<err>must be greater than) (?<val>\d+)/,
21
- /\A(?<err>must be greater than or equal to) (?<val>\d+)/,
22
- /\A(?<err>must include) (?<val>.+)/,
23
- /\A(?<err>must be less than) (?<val>\d+)/,
24
- /\A(?<err>must be less than or equal to) (?<val>\d+)/,
25
- /\A(?<err>size cannot be greater than) (?<val>\d+)/,
26
- /\A(?<err>size cannot be less than) (?<val>\d+)/,
27
- /\A(?<err>size must be) (?<val>\d+)/,
28
- /\A(?<err>length must be) (?<val>\d+)/
29
- ].freeze
30
-
31
- LIST_MATCHERS = [
32
- /\A(?<err>must not be one of): (?<val>.+)/,
33
- /\A(?<err>must be one of): (?<val>.+)/,
34
- /\A(?<err>size must be within) (?<val>.+)/,
35
- /\A(?<err>length must be within) (?<val>.+)/
36
- ].freeze
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 = to_key(@message)
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
- VALUE_MATCHERS.each do |matcher|
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 = to_key(data[:err])
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
- LIST_MATCHERS.each do |matcher|
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 = to_key(data[:err])
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
- def to_key(msg)
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
- result = MessageParser.new(err_message).parse
90
- key, msg, payload = result.to_a
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ErrorNormalizer
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -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.1.1
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-07 00:00:00.000000000 Z
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: