lev 10.1.0 → 12.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: e9b8ecaa0018e8014f478eff02949764ffaf1ad73f50c9d64be7fd6889b9758d
4
+ data.tar.gz: ff47d80e42f5ef65335c4da2636efe6ee0bc13a78a650b1b13833e5e1aa84763
5
5
  SHA512:
6
- metadata.gz: 9dc7506db7fe12a5122596ea9f6cdf6682bc2f601f6b89d6dc26c49c1733e53a3d74ff0679430877deaf94c1009ab22a2bde64432cd8c946a5790237177c9f25
7
- data.tar.gz: 53125d7cb41f17b27539b45802d4ec1dff132434c4d4dcdddc0294128c8a973a02f2bea2df8a852d986b5ecb4e46462af3d552198846a8c2f8caf10ab255d400
6
+ metadata.gz: 858c6dba66a94ba31b6129f3602d55d83e7cc713fe9a7710f3e6109c7e80cb3cc67a568c4257d9d44d32c90c10c17d943700ef36e9eed1e82b114ca9f5fa9f9c
7
+ data.tar.gz: 74bdcc356356641f04717adbcf74c7c3945522ab0b472ed8eef4cba407f55022cea2541092c4bca0a70deac1cb3d730454a1d98dfcf28a73e631abc6a3c41157
@@ -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 = '12.0.0'
3
3
  end
data/lib/lev.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "action_view"
2
2
  require "active_job"
3
3
  require "transaction_isolation"
4
- require "transaction_retry"
4
+ require "open_stax_transaction_retry"
5
5
  require "active_attr"
6
6
  require "hashie"
7
7
 
@@ -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"
@@ -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
data/spec/spec_helper.rb CHANGED
@@ -26,9 +26,9 @@ end
26
26
  require 'lev'
27
27
  require 'byebug'
28
28
 
29
- require 'transaction_retry'
29
+ require 'open_stax_transaction_retry'
30
30
 
31
- TransactionRetry.apply_activerecord_patch
31
+ OpenStaxTransactionRetry.apply_activerecord_patch
32
32
 
33
33
  Dir[(File.expand_path('../support', __FILE__)) + ("/**/*.rb")].each { |f| require f }
34
34
 
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lev
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.1.0
4
+ version: 12.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-31 00:00:00.000000000 Z
11
+ date: 2023-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activemodel
14
+ name: actionpack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,63 +25,63 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activerecord
28
+ name: active_attr
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '4.2'
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '4.2'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: actionpack
42
+ name: activejob
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '4.2'
47
+ version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '4.2'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: activejob
56
+ name: activemodel
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '6.1'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '6.1'
69
69
  - !ruby/object:Gem::Dependency
70
- name: transaction_isolation
70
+ name: activerecord
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '4.2'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '4.2'
83
83
  - !ruby/object:Gem::Dependency
84
- name: transaction_retry
84
+ name: hashie
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: active_attr
98
+ name: openstax_transaction_retry
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: hashie
112
+ name: transaction_isolation
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -137,21 +137,21 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: rake
140
+ name: jobba
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '2.0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '2.0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: rspec
154
+ name: rake
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -165,7 +165,7 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: sqlite3
168
+ name: rspec
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - ">="
@@ -179,19 +179,19 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
- name: jobba
182
+ name: sqlite3
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
186
186
  - !ruby/object:Gem::Version
187
- version: '1.5'
187
+ version: '0'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
- version: '1.5'
194
+ version: '0'
195
195
  description: Ride the rails but don't touch them.
196
196
  email:
197
197
  - jps@kindlinglabs.com
@@ -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
@@ -250,7 +249,7 @@ homepage: http://github.com/lml/lev
250
249
  licenses:
251
250
  - MIT
252
251
  metadata: {}
253
- post_install_message:
252
+ post_install_message:
254
253
  rdoc_options: []
255
254
  require_paths:
256
255
  - lib
@@ -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
269
- signing_key:
267
+ rubygems_version: 3.4.6
268
+ signing_key:
270
269
  specification_version: 4
271
270
  summary: Ride the rails but don't touch them.
272
271
  test_files:
273
272
  - spec/active_job_routines_spec.rb
274
- - spec/paramify_handler_spec.rb
275
- - spec/spec_helper.rb
276
- - spec/sprocket_spec.rb
273
+ - spec/active_model_errors_spec.rb
277
274
  - spec/create_sprocket_spec.rb
278
- - spec/outputs_spec.rb
279
275
  - spec/deep_merge_spec.rb
276
+ - spec/delegates_to_spec.rb
277
+ - spec/outputs_spec.rb
278
+ - spec/paramify_handler_spec.rb
279
+ - spec/routine_spec.rb
280
+ - spec/spec_helper.rb
280
281
  - spec/sprocket_handler_spec.rb
282
+ - spec/sprocket_spec.rb
281
283
  - 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
284
  - spec/support/create_sprocket.rb
286
285
  - spec/support/delegated_routine.rb
287
- - spec/support/sprocket.rb
286
+ - spec/support/delegating_routine.rb
288
287
  - spec/support/paramify_handler_a.rb
289
288
  - spec/support/paramify_handler_b.rb
290
- - spec/support/delegating_routine.rb
289
+ - spec/support/sprocket.rb
290
+ - spec/support/sprocket_handler.rb
291
291
  - spec/transaction_spec.rb
292
- - spec/delegates_to_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