lev 10.1.0 → 11.0.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: fb4ccab91175edafaeff83e3bab8ab84e5a650ebc88b5000bf848ff1ad171d49
4
- data.tar.gz: ce48c8cc00ed7edfa6076b5ba91ddbf11933f0a4b9f02e65dd6548ab69fc5b6c
3
+ metadata.gz: 6a420c65f32a06c875e0e5069340f8cf1cc38505d9862a9ecbe20aede96059a2
4
+ data.tar.gz: 51f9c9746e69f4fc818f8e0d0c33e22a0c62d1a4f87c14b37d3b5645118a40ca
5
5
  SHA512:
6
- metadata.gz: 9dc7506db7fe12a5122596ea9f6cdf6682bc2f601f6b89d6dc26c49c1733e53a3d74ff0679430877deaf94c1009ab22a2bde64432cd8c946a5790237177c9f25
7
- data.tar.gz: 53125d7cb41f17b27539b45802d4ec1dff132434c4d4dcdddc0294128c8a973a02f2bea2df8a852d986b5ecb4e46462af3d552198846a8c2f8caf10ab255d400
6
+ metadata.gz: dd09071d958ae2590c604f2e6708b0942b06ecc97ff50be00d6a37863945543e56393a58f3a15b4664463104ba1064216cd66937bee00c1a3acdadf41596bfa3
7
+ data.tar.gz: 668e9e10ea0285ad953b3080484360017d487484f8771e7af1eb235ccdb1e1244ec7f563c1ed59df8148926a5284d2e89b7016c5376b702335ad2de9b88aea4a
data/lib/lev.rb CHANGED
@@ -9,7 +9,6 @@ require "lev/version"
9
9
  require "lev/object"
10
10
  require "lev/utilities"
11
11
  require "lev/exceptions"
12
- require "lev/better_active_model_errors"
13
12
  require "lev/term_mapper"
14
13
  require "lev/outputs"
15
14
  require "lev/routine"
@@ -5,16 +5,16 @@ module Lev
5
5
  def self.transfer(source, target_routine, input_mapper, fail_if_errors=false)
6
6
  case source
7
7
  when ActiveRecord::Base, Lev::Paramifier
8
- source.errors.each_with_type_and_message do |attribute, type, message|
8
+ source.errors.each do |error|
9
9
  target_routine.nonfatal_error(
10
- code: type,
10
+ code: error.type,
11
11
  data: {
12
12
  model: source,
13
- attribute: attribute
13
+ attribute: error.attribute
14
14
  },
15
15
  kind: :activerecord,
16
- message: message,
17
- offending_inputs: input_mapper.map(attribute)
16
+ message: error.message,
17
+ offending_inputs: input_mapper.map(error.attribute)
18
18
  )
19
19
  end
20
20
  when Lev::Errors
@@ -5,15 +5,14 @@ module Lev
5
5
  def self.translate(error)
6
6
  case error.kind
7
7
  when :activerecord
8
- model = error.data[:model]
9
8
  attribute = error.data[:attribute]
10
- # TODO error.message might always be populated now -- really need the other call after ||?
11
- message = error.message || Lev::BetterActiveModelErrors.generate_message(model, attribute, error.code)
12
- Lev::BetterActiveModelErrors.full_message(model, attribute, message)
9
+ message = error.message
10
+ model = error.data[:model]
11
+ ActiveModel::Error.full_message(attribute, message, model)
13
12
  else
14
13
  message = error.message.to_s
15
14
  message.empty? ? error.code.to_s : message
16
- end
15
+ end
17
16
  end
18
17
 
19
18
  end
data/lib/lev/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lev
2
- VERSION = '10.1.0'
2
+ VERSION = '11.0.0'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe 'BetterActiveModelErrors' do
3
+ RSpec.describe 'ActiveModelErrors' do
4
4
  class DummyModel
5
5
  def self.human_attribute_name(attr, default='')
6
6
  return attr.capitalize
@@ -8,10 +8,11 @@ RSpec.describe 'BetterActiveModelErrors' do
8
8
  end
9
9
 
10
10
  let(:test_model) { DummyModel.new }
11
- let(:errors) { Lev::BetterActiveModelErrors.new(test_model) }
11
+ let(:errors) { ActiveModel::Errors.new(test_model) }
12
12
 
13
13
  it 'can record errors' do
14
- errors[:foo] = 'bar'
14
+ errors.add(:foo, 'bar')
15
+ expect(errors[:foo]).to eq ['bar']
15
16
  expect(errors.any?).to be(true)
16
17
  end
17
18
 
@@ -24,13 +25,13 @@ RSpec.describe 'BetterActiveModelErrors' do
24
25
  it 'duplicates when copy called' do
25
26
  model = OpenStruct.new
26
27
 
27
- error = Lev::BetterActiveModelErrors.new(model)
28
- error.set(:code, 'error')
29
- expect(error.get(:code)).to eq 'error'
28
+ error = ActiveModel::Errors.new(model)
29
+ error.add(:code, 'error')
30
+ expect(error[:code]).to eq ['error']
30
31
 
31
- other = Lev::BetterActiveModelErrors.new(model)
32
- other.set(:code, 'warning')
32
+ other = ActiveModel::Errors.new(model)
33
+ other.add(:code, 'warning')
33
34
  error.copy!(other)
34
- expect(error.get(:code)).to eq 'warning'
35
+ expect(error[:code]).to eq ['warning']
35
36
  end
36
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lev
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.1.0
4
+ version: 11.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-31 00:00:00.000000000 Z
11
+ date: 2021-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -206,7 +206,6 @@ files:
206
206
  - lib/lev/active_job.rb
207
207
  - lib/lev/active_job/base.rb
208
208
  - lib/lev/active_job/configured_job.rb
209
- - lib/lev/better_active_model_errors.rb
210
209
  - lib/lev/delegate_to_routine.rb
211
210
  - lib/lev/error.rb
212
211
  - lib/lev/error_transferer.rb
@@ -227,7 +226,7 @@ files:
227
226
  - lib/lev/utilities.rb
228
227
  - lib/lev/version.rb
229
228
  - spec/active_job_routines_spec.rb
230
- - spec/better_active_model_errors_spec.rb
229
+ - spec/active_model_errors_spec.rb
231
230
  - spec/create_sprocket_spec.rb
232
231
  - spec/deep_merge_spec.rb
233
232
  - spec/delegates_to_spec.rb
@@ -265,28 +264,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
265
264
  - !ruby/object:Gem::Version
266
265
  version: '0'
267
266
  requirements: []
268
- rubygems_version: 3.0.3
267
+ rubygems_version: 3.2.7
269
268
  signing_key:
270
269
  specification_version: 4
271
270
  summary: Ride the rails but don't touch them.
272
271
  test_files:
273
- - spec/active_job_routines_spec.rb
274
- - spec/paramify_handler_spec.rb
275
- - spec/spec_helper.rb
276
- - spec/sprocket_spec.rb
277
272
  - spec/create_sprocket_spec.rb
273
+ - spec/paramify_handler_spec.rb
278
274
  - spec/outputs_spec.rb
279
- - spec/deep_merge_spec.rb
280
- - spec/sprocket_handler_spec.rb
281
- - spec/statused_routines_spec.rb
282
- - spec/better_active_model_errors_spec.rb
283
- - spec/routine_spec.rb
284
- - spec/support/sprocket_handler.rb
285
- - spec/support/create_sprocket.rb
286
- - spec/support/delegated_routine.rb
287
- - spec/support/sprocket.rb
275
+ - spec/transaction_spec.rb
288
276
  - spec/support/paramify_handler_a.rb
277
+ - spec/support/delegated_routine.rb
289
278
  - spec/support/paramify_handler_b.rb
279
+ - spec/support/create_sprocket.rb
280
+ - spec/support/sprocket_handler.rb
290
281
  - spec/support/delegating_routine.rb
291
- - spec/transaction_spec.rb
282
+ - spec/support/sprocket.rb
283
+ - spec/statused_routines_spec.rb
284
+ - spec/active_model_errors_spec.rb
292
285
  - spec/delegates_to_spec.rb
286
+ - spec/active_job_routines_spec.rb
287
+ - spec/deep_merge_spec.rb
288
+ - spec/routine_spec.rb
289
+ - spec/sprocket_handler_spec.rb
290
+ - spec/spec_helper.rb
291
+ - spec/sprocket_spec.rb
@@ -1,421 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- require 'active_support/core_ext/array/wrap'
4
- require 'active_support/core_ext/array/conversions'
5
- require 'active_support/core_ext/string/inflections'
6
- require 'active_support/core_ext/object/blank'
7
- require 'active_support/core_ext/hash/reverse_merge'
8
- require 'active_support/ordered_hash'
9
-
10
- module Lev
11
- # == Better Errors
12
- #
13
- # Same as ActiveModel::Errors but also retains error types
14
- #
15
- # Provides a modified +OrderedHash+ that you can include in your object
16
- # for handling error messages and interacting with Action Pack helpers.
17
- #
18
- # A minimal implementation could be:
19
- #
20
- # class Person
21
- #
22
- # # Required dependency for ActiveModel::Errors
23
- # extend ActiveModel::Naming
24
- #
25
- # def initialize
26
- # @errors = ActiveModel::Errors.new(self)
27
- # end
28
- #
29
- # attr_accessor :name
30
- # attr_reader :errors
31
- #
32
- # def validate!
33
- # errors.add(:name, "can not be nil") if name == nil
34
- # end
35
- #
36
- # # The following methods are needed to be minimally implemented
37
- #
38
- # def read_attribute_for_validation(attr)
39
- # send(attr)
40
- # end
41
- #
42
- # def Person.human_attribute_name(attr, options = {})
43
- # attr
44
- # end
45
- #
46
- # def Person.lookup_ancestors
47
- # [self]
48
- # end
49
- #
50
- # end
51
- #
52
- # The last three methods are required in your object for Errors to be
53
- # able to generate error messages correctly and also handle multiple
54
- # languages. Of course, if you extend your object with ActiveModel::Translation
55
- # you will not need to implement the last two. Likewise, using
56
- # ActiveModel::Validations will handle the validation related methods
57
- # for you.
58
- #
59
- # The above allows you to do:
60
- #
61
- # p = Person.new
62
- # p.validate! # => ["can not be nil"]
63
- # p.errors.full_messages # => ["name can not be nil"]
64
- # # etc..
65
- class BetterActiveModelErrors
66
- include Enumerable
67
-
68
- CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
69
-
70
- attr_reader :messages
71
- attr_reader :types
72
-
73
- # Pass in the instance of the object that is using the errors object.
74
- #
75
- # class Person
76
- # def initialize
77
- # @errors = ActiveModel::Errors.new(self)
78
- # end
79
- # end
80
- def initialize(base)
81
- @base = base
82
- @types = ActiveSupport::OrderedHash.new
83
- @messages = ActiveSupport::OrderedHash.new
84
- end
85
-
86
- # copy & details are needed to match `ActiveModel::Errors` interface
87
- def copy!(other)
88
- initialize_dup(other)
89
- end
90
- def details
91
- {}
92
- end
93
-
94
- def initialize_dup(other)
95
- @types = other.types.dup
96
- @messages = other.messages.dup
97
- end
98
-
99
- # Backport dup from 1.9 so that #initialize_dup gets called
100
- unless Object.respond_to?(:initialize_dup, true)
101
- def dup # :nodoc:
102
- copy = super
103
- copy.initialize_dup(self)
104
- copy
105
- end
106
- end
107
-
108
- # Clear the messages
109
- def clear
110
- types.clear
111
- messages.clear
112
- end
113
-
114
- # Do the error messages include an error with key +error+?
115
- def include?(error)
116
- (v = messages[error.to_sym]) && v.any?
117
- end
118
- alias :has_key? :include?
119
-
120
- # Get messages for +key+
121
- def get(key)
122
- messages[key.to_sym]
123
- end
124
-
125
- def get_type(key)
126
- types[key.to_sym]
127
- end
128
-
129
- # Set messages for +key+ to +value+
130
- def set(key, value)
131
- types[key.to_sym] = (value == [] ? [] : (value.is_a?(Symbol) ? value : nil))
132
- messages[key.to_sym] = value
133
- end
134
-
135
- # Delete messages for +key+
136
- def delete(key)
137
- key = key.to_sym
138
- types.delete(key)
139
- messages.delete(key)
140
- end
141
-
142
- # When passed a symbol or a name of a method, returns an array of errors
143
- # for the method.
144
- #
145
- # p.errors[:name] # => ["can not be nil"]
146
- # p.errors['name'] # => ["can not be nil"]
147
- def [](attribute)
148
- get(attribute.to_sym) || set(attribute.to_sym, [])
149
- end
150
-
151
- # Adds to the supplied attribute the supplied error message.
152
- #
153
- # p.errors[:name] = "must be set"
154
- # p.errors[:name] # => ['must be set']
155
- def []=(attribute, error)
156
- self[attribute] << error
157
- end
158
-
159
- # Iterates through each error key, value pair in the error messages hash.
160
- # Yields the attribute and the error for that attribute. If the attribute
161
- # has more than one error message, yields once for each error message.
162
- #
163
- # p.errors.add(:name, "can't be blank")
164
- # p.errors.each do |attribute, errors_array|
165
- # # Will yield :name and "can't be blank"
166
- # end
167
- #
168
- # p.errors.add(:name, "must be specified")
169
- # p.errors.each do |attribute, errors_array|
170
- # # Will yield :name and "can't be blank"
171
- # # then yield :name and "must be specified"
172
- # end
173
- def each
174
- messages.each_key do |attribute|
175
- self[attribute].each { |error| yield attribute, error }
176
- end
177
- end
178
-
179
- def each_with_type_and_message
180
- types.each_key do |attribute|
181
- for ii in 0..self.types[attribute].size-1
182
- yield attribute, self.types[attribute][ii], self.messages[attribute][ii]
183
- end
184
- end
185
- end
186
-
187
- # Returns the number of error messages.
188
- #
189
- # p.errors.add(:name, "can't be blank")
190
- # p.errors.size # => 1
191
- # p.errors.add(:name, "must be specified")
192
- # p.errors.size # => 2
193
- def size
194
- values.flatten.size
195
- end
196
-
197
- # Returns all message values
198
- def values
199
- messages.values
200
- end
201
-
202
- # Returns all message keys
203
- def keys
204
- messages.keys
205
- end
206
-
207
- # Returns an array of error messages, with the attribute name included
208
- #
209
- # p.errors.add(:name, "can't be blank")
210
- # p.errors.add(:name, "must be specified")
211
- # p.errors.to_a # => ["name can't be blank", "name must be specified"]
212
- def to_a
213
- full_messages
214
- end
215
-
216
- # Returns the number of error messages.
217
- # p.errors.add(:name, "can't be blank")
218
- # p.errors.count # => 1
219
- # p.errors.add(:name, "must be specified")
220
- # p.errors.count # => 2
221
- def count
222
- to_a.size
223
- end
224
-
225
- # Returns true if no errors are found, false otherwise.
226
- # If the error message is a string it can be empty.
227
- def empty?
228
- all? { |k, v| v && v.empty? && !v.is_a?(String) }
229
- end
230
- alias_method :blank?, :empty?
231
-
232
- # Returns an xml formatted representation of the Errors hash.
233
- #
234
- # p.errors.add(:name, "can't be blank")
235
- # p.errors.add(:name, "must be specified")
236
- # p.errors.to_xml
237
- # # =>
238
- # # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
239
- # # <errors>
240
- # # <error>name can't be blank</error>
241
- # # <error>name must be specified</error>
242
- # # </errors>
243
- def to_xml(options={})
244
- to_a.to_xml options.reverse_merge(:root => "errors", :skip_types => true)
245
- end
246
-
247
- # Returns an ActiveSupport::OrderedHash that can be used as the JSON representation for this object.
248
- def as_json(options=nil)
249
- to_hash
250
- end
251
-
252
- def to_hash
253
- messages.dup
254
- end
255
-
256
- def to_s
257
- inspect
258
- end
259
-
260
- # Adds +message+ to the error messages on +attribute+. More than one error can be added to the same
261
- # +attribute+.
262
- # If no +message+ is supplied, <tt>:invalid</tt> is assumed.
263
- #
264
- # If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+).
265
- # If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
266
- def add(attribute, message = nil, options = {})
267
- normalized_message = normalize_message(attribute, message, options)
268
- if options[:strict]
269
- raise ActiveModel::StrictValidationFailed, full_message(attribute, normalized_message)
270
- end
271
-
272
- self[attribute] << normalized_message
273
- self.types[attribute.to_sym] << message.try(:to_sym)
274
- end
275
-
276
- # Will add an error message to each of the attributes in +attributes+ that is empty.
277
- def add_on_empty(attributes, options = {})
278
- [attributes].flatten.each do |attribute|
279
- value = @base.send(:read_attribute_for_validation, attribute)
280
- is_empty = value.respond_to?(:empty?) ? value.empty? : false
281
- add(attribute, :empty, options) if value.nil? || is_empty
282
- end
283
- end
284
-
285
- # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?).
286
- def add_on_blank(attributes, options = {})
287
- [attributes].flatten.each do |attribute|
288
- value = @base.send(:read_attribute_for_validation, attribute)
289
- add(attribute, :blank, options) if value.blank?
290
- end
291
- end
292
-
293
- # Returns true if an error on the attribute with the given message is present, false otherwise.
294
- # +message+ is treated the same as for +add+.
295
- # p.errors.add :name, :blank
296
- # p.errors.added? :name, :blank # => true
297
- def added?(attribute, message = nil, options = {})
298
- message = normalize_message(attribute, message, options)
299
- self[attribute].include? message
300
- end
301
-
302
- # Returns all the full error messages in an array.
303
- #
304
- # class Company
305
- # validates_presence_of :name, :address, :email
306
- # validates_length_of :name, :in => 5..30
307
- # end
308
- #
309
- # company = Company.create(:address => '123 First St.')
310
- # company.errors.full_messages # =>
311
- # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
312
- def full_messages
313
- map { |attribute, message| full_message(attribute, message) }
314
- end
315
-
316
- # Returns a full message for a given attribute.
317
- #
318
- # company.errors.full_message(:name, "is invalid") # =>
319
- # "Name is invalid"
320
- def full_message(attribute, message)
321
- self.class.full_message(@base, attribute, message)
322
- end
323
-
324
- def self.full_message(model, attribute, message)
325
- return message if attribute == :base
326
- attr_name = attribute.to_s.gsub('.', '_').humanize
327
- attr_name = model.class.human_attribute_name(attribute, default: attr_name)
328
- I18n.t(:"errors.format", {
329
- default: "%{attribute} %{message}",
330
- attribute: attr_name,
331
- message: message
332
- })
333
- end
334
-
335
- # Translates an error message in its default scope
336
- # (<tt>activemodel.errors.messages</tt>).
337
- #
338
- # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
339
- # if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not
340
- # there also, it returns the translation of the default message
341
- # (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model name,
342
- # translated attribute name and the value are available for interpolation.
343
- #
344
- # When using inheritance in your models, it will check all the inherited
345
- # models too, but only if the model itself hasn't been found. Say you have
346
- # <tt>class Admin < User; end</tt> and you wanted the translation for
347
- # the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
348
- # it looks for these translations:
349
- #
350
- # * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
351
- # * <tt>activemodel.errors.models.admin.blank</tt>
352
- # * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
353
- # * <tt>activemodel.errors.models.user.blank</tt>
354
- # * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
355
- # * <tt>activemodel.errors.messages.blank</tt>
356
- # * <tt>errors.attributes.title.blank</tt>
357
- # * <tt>errors.messages.blank</tt>
358
- #
359
- def generate_message(attribute, type = :invalid, options = {})
360
- self.class.generate_message(@base, attribute, type, options)
361
- end
362
-
363
- # TODO maybe don't need this method split out any more?
364
- def self.generate_message(model, attribute, type = :invalid, options = {})
365
- type = options.delete(:message) if options[:message].is_a?(Symbol)
366
- attribute = attribute.to_sym
367
- if model.class.respond_to?(:i18n_scope)
368
- defaults = model.class.lookup_ancestors.map do |klass|
369
- [ :"#{model.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
370
- :"#{model.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
371
- end
372
- else
373
- defaults = []
374
- end
375
-
376
- defaults << options.delete(:message)
377
- defaults << :"#{model.class.i18n_scope}.errors.messages.#{type}" if model.class.respond_to?(:i18n_scope)
378
- defaults << :"errors.attributes.#{attribute}.#{type}"
379
- defaults << :"errors.messages.#{type}"
380
-
381
- defaults.compact!
382
- defaults.flatten!
383
-
384
- key = defaults.shift
385
- value = (attribute != :base ? model.send(:read_attribute_for_validation, attribute) : nil)
386
-
387
- options = {
388
- :default => defaults,
389
- :model => model.class.model_name.human,
390
- :attribute => model.class.human_attribute_name(attribute),
391
- :value => value
392
- }.merge(options)
393
-
394
- I18n.translate(key, options)
395
- end
396
-
397
- private
398
- def normalize_message(attribute, message, options)
399
- message ||= :invalid
400
-
401
- if message.is_a?(Symbol)
402
- generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
403
- elsif message.is_a?(Proc)
404
- message.call
405
- else
406
- message
407
- end
408
- end
409
- end
410
-
411
- class StrictValidationFailed < StandardError
412
- end
413
- end
414
-
415
- module ActiveModel
416
- module Validations
417
- def errors
418
- @errors ||= Lev::BetterActiveModelErrors.new(self)
419
- end
420
- end
421
- end