lev 10.1.0 → 11.0.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 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