lotus-validations 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +60 -2
- data/lib/lotus/validations.rb +69 -54
- data/lib/lotus/validations/{attribute_validator.rb → attribute.rb} +60 -45
- data/lib/lotus/validations/attribute_set.rb +51 -0
- data/lib/lotus/validations/attributes.rb +38 -0
- data/lib/lotus/validations/coercions.rb +3 -2
- data/lib/lotus/validations/errors.rb +2 -4
- data/lib/lotus/validations/version.rb +1 -1
- data/lotus-validations.gemspec +2 -2
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8038d2ee15fc8a3e5205d528f56db97024928714
|
4
|
+
data.tar.gz: 9136c6849b93c7869c4dbea6d91b163cce353a3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 904a4cab5995195acfe618eb621ee6d48cd1a3746fb0546aa4f16ac983f67109c1969026bbfc0f48337006922eb9cd8391a8fecdf56afbfed77ba175f6a3d86c
|
7
|
+
data.tar.gz: 5bb93ddc815abdb33028dcbf16896acf276cdb75bcf4eb414e61ff28932b7ad90c1782cb1de57bdcdd8d1c925e60eaf38417b27747a92c99b7ea2c727d8c5ec9
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Lotus::Validations
|
2
|
+
Validations mixin for Ruby objects
|
3
|
+
|
4
|
+
## v0.2.0 - 2014-11-23
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Skip attribute whitelisting when a validator does not define any attribute
|
7
|
+
- [Luca Guidi] Official support for Rubinius 2.3+
|
8
|
+
- [Luca Guidi] Implemented `#each` in order to allow bulk operations on attributes
|
9
|
+
- [Luca Guidi] Implemented `#to_h` to make validations usable by other libraries
|
10
|
+
- [Luca Guidi] Made `#initialize` to accept Hashes with strings as keys, but only for declared attributes
|
11
|
+
- [Luca Guidi] Lazy coercions, from now on `valid?` is not required to obtain a coerced value from a single attribute
|
12
|
+
- [Rik Tonnard] Made validators reusable by allowing infinite inclusion
|
13
|
+
|
14
|
+
## v0.1.0 - 2014-10-23
|
15
|
+
### Added
|
16
|
+
- [Luca Guidi] Made `#initialize` to accept any object that implements `#to_h`
|
17
|
+
- [Luca Guidi] Custom coercions for user defined classes
|
18
|
+
- [Luca Guidi] Raise an exception at the load time when a validation is not recognized
|
19
|
+
- [Luca Guidi] Allow validators inheritance
|
20
|
+
- [Luca Guidi] Confirmation validation
|
21
|
+
- [Luca Guidi] Exclusion validation
|
22
|
+
- [Luca Guidi] Size validation
|
23
|
+
- [Luca Guidi] Acceptance validation
|
24
|
+
- [Jeremy Stephens] Inclusion validation
|
25
|
+
- [Luca Guidi] Format validation
|
26
|
+
- [Luca Guidi] Presence validation
|
27
|
+
- [Luca Guidi] Coercions
|
28
|
+
- [Luca Guidi] Basic module inclusion
|
29
|
+
- [Luca Guidi] Official support for JRuby 1.7+ (with 2.0 mode)
|
30
|
+
- [Luca Guidi] Official support for MRI 2.0+
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
- [Jeremy Stephens] Ensure to not fail validations when coerce falsey values
|
34
|
+
- [Luca Guidi] Ensure `Lotus::Validations#valid?` to be idempotent
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Validations mixins for objects
|
|
22
22
|
|
23
23
|
## Rubies
|
24
24
|
|
25
|
-
__Lotus::Validations__ supports Ruby (MRI) 2
|
25
|
+
__Lotus::Validations__ supports Ruby (MRI) 2+, JRuby 1.7 (with 2.0 mode) and Rubinius 2.3.0+.
|
26
26
|
|
27
27
|
## Installation
|
28
28
|
|
@@ -311,7 +311,7 @@ class Signup
|
|
311
311
|
|
312
312
|
attribute :ssn, size: 11 # exact match
|
313
313
|
attribute :password, size: 8..64 # range
|
314
|
-
attribute :avatar, size
|
314
|
+
attribute :avatar, size: 1..(5 * MEGABYTE)
|
315
315
|
end
|
316
316
|
|
317
317
|
signup = Signup.new(password: 'a-very-long-password')
|
@@ -331,6 +331,64 @@ The other reason is that this isn't an effective way to ensure uniqueness of a v
|
|
331
331
|
|
332
332
|
Please read more at: [The Perils of Uniqueness Validations](http://robots.thoughtbot.com/the-perils-of-uniqueness-validations).
|
333
333
|
|
334
|
+
### Composable validations
|
335
|
+
|
336
|
+
Validations can be reused via composition:
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
require 'lotus/validations'
|
340
|
+
|
341
|
+
module NameValidations
|
342
|
+
include Lotus::Validations
|
343
|
+
|
344
|
+
attribute :name, presence: true
|
345
|
+
end
|
346
|
+
|
347
|
+
module EmailValidations
|
348
|
+
include Lotus::Validations
|
349
|
+
|
350
|
+
attribute :email, presence: true, format: /.../
|
351
|
+
end
|
352
|
+
|
353
|
+
module PasswordValidations
|
354
|
+
include Lotus::Validations
|
355
|
+
|
356
|
+
# We validate only the presence here
|
357
|
+
attribute :password, presence: true
|
358
|
+
end
|
359
|
+
|
360
|
+
module CommonValidations
|
361
|
+
include EmailValidations
|
362
|
+
include PasswordValidations
|
363
|
+
end
|
364
|
+
|
365
|
+
# A valid signup requires:
|
366
|
+
# * name (presence)
|
367
|
+
# * email (presence and format)
|
368
|
+
# * password (presence and confirmation)
|
369
|
+
class Signup
|
370
|
+
include NameValidations
|
371
|
+
include CommonValidations
|
372
|
+
|
373
|
+
# We decorate PasswordValidations behavior, by requiring the confirmation too.
|
374
|
+
# This additional validation is active only in this case.
|
375
|
+
attribute :password, confirmation: true
|
376
|
+
end
|
377
|
+
|
378
|
+
# A valid signin requires:
|
379
|
+
# * email (presence)
|
380
|
+
# * password (presence)
|
381
|
+
class Signin
|
382
|
+
include CommonValidations
|
383
|
+
end
|
384
|
+
|
385
|
+
# A valid "forgot password" requires:
|
386
|
+
# * email (presence)
|
387
|
+
class ForgotPassword
|
388
|
+
include EmailValidations
|
389
|
+
end
|
390
|
+
```
|
391
|
+
|
334
392
|
### Complete example
|
335
393
|
|
336
394
|
```ruby
|
data/lib/lotus/validations.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
+
require 'lotus/utils/hash'
|
1
2
|
require 'lotus/validations/version'
|
3
|
+
require 'lotus/validations/attribute_set'
|
4
|
+
require 'lotus/validations/attributes'
|
5
|
+
require 'lotus/validations/attribute'
|
2
6
|
require 'lotus/validations/errors'
|
3
|
-
require 'lotus/validations/attribute_validator'
|
4
7
|
|
5
8
|
module Lotus
|
6
9
|
# Lotus::Validations is a set of lightweight validations for Ruby objects.
|
7
10
|
#
|
8
11
|
# @since 0.1.0
|
9
12
|
module Validations
|
10
|
-
|
11
13
|
# Override Ruby's hook for modules.
|
12
14
|
#
|
13
15
|
# @param base [Class] the target action
|
@@ -24,6 +26,45 @@ module Lotus
|
|
24
26
|
#
|
25
27
|
# @since 0.1.0
|
26
28
|
module ClassMethods
|
29
|
+
# Override Ruby's hook for modules. When a module includes
|
30
|
+
# Lotus::Validations and it is included in a class or module, this passes
|
31
|
+
# the attributes from the module to the base.
|
32
|
+
#
|
33
|
+
# @param base [Class] the target action
|
34
|
+
#
|
35
|
+
# @since x.x.x
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
# @see http://www.ruby-doc.org/core/Module.html#method-i-included
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# require 'lotus/validations'
|
42
|
+
#
|
43
|
+
# module NameValidations
|
44
|
+
# include Lotus::Validations
|
45
|
+
#
|
46
|
+
# attribute :name, presence: true
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# class Signup
|
50
|
+
# include NameValidations
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# signup = Signup.new(name: '')
|
54
|
+
# signup.valid? # => false
|
55
|
+
#
|
56
|
+
# signup = Signup.new(name: 'Luca')
|
57
|
+
# signup.valid? # => true
|
58
|
+
def included(base)
|
59
|
+
base.class_eval do
|
60
|
+
include Lotus::Validations
|
61
|
+
end
|
62
|
+
|
63
|
+
attributes.each do |attribute, options|
|
64
|
+
base.attribute attribute, options
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
27
68
|
# Define an attribute
|
28
69
|
#
|
29
70
|
# @param name [#to_sym] the name of the attribute
|
@@ -206,11 +247,11 @@ module Lotus
|
|
206
247
|
# signup = Signup.new(password: 'short')
|
207
248
|
# signup.valid? # => false
|
208
249
|
def attribute(name, options = {})
|
209
|
-
attributes
|
250
|
+
attributes.add(name, options)
|
210
251
|
|
211
252
|
class_eval %{
|
212
253
|
def #{ name }
|
213
|
-
@attributes
|
254
|
+
@attributes.get(:#{ name })
|
214
255
|
end
|
215
256
|
}
|
216
257
|
end
|
@@ -223,35 +264,7 @@ module Lotus
|
|
223
264
|
# @since 0.1.0
|
224
265
|
# @api private
|
225
266
|
def attributes
|
226
|
-
@attributes ||=
|
227
|
-
end
|
228
|
-
|
229
|
-
# Checks at the loading time if the user defined validations are recognized
|
230
|
-
#
|
231
|
-
# @param name [Symbol] the attribute name
|
232
|
-
# @param options [Hash] the set of validations associated with the given attribute
|
233
|
-
#
|
234
|
-
# @raise [ArgumentError] if at least one of the validations are not
|
235
|
-
# recognized
|
236
|
-
#
|
237
|
-
# @since 0.1.0
|
238
|
-
# @api private
|
239
|
-
def validate_options!(name, options)
|
240
|
-
if (unknown = (options.keys - validations)) && unknown.any?
|
241
|
-
raise ArgumentError.new(%(Unknown validation(s): #{ unknown.join ', ' } for "#{ name }" attribute))
|
242
|
-
end
|
243
|
-
|
244
|
-
options
|
245
|
-
end
|
246
|
-
|
247
|
-
# Names of the implemented validations
|
248
|
-
#
|
249
|
-
# @return [Array]
|
250
|
-
#
|
251
|
-
# @since 0.1.0
|
252
|
-
# @api private
|
253
|
-
def validations
|
254
|
-
[:presence, :acceptance, :format, :inclusion, :exclusion, :confirmation, :size, :type]
|
267
|
+
@attributes ||= AttributeSet.new
|
255
268
|
end
|
256
269
|
end
|
257
270
|
|
@@ -346,7 +359,7 @@ module Lotus
|
|
346
359
|
#
|
347
360
|
# signup.name # => "Luca"
|
348
361
|
def initialize(attributes)
|
349
|
-
@attributes = attributes
|
362
|
+
@attributes = Attributes.new(defined_attributes, attributes)
|
350
363
|
@errors = Errors.new
|
351
364
|
end
|
352
365
|
|
@@ -358,40 +371,42 @@ module Lotus
|
|
358
371
|
def valid?
|
359
372
|
@errors.clear
|
360
373
|
|
361
|
-
|
362
|
-
|
374
|
+
@attributes.each do |name, attribute|
|
375
|
+
@errors.add(name, *attribute.validate)
|
363
376
|
end
|
364
377
|
|
365
378
|
@errors.empty?
|
366
379
|
end
|
367
380
|
|
368
|
-
|
369
|
-
# Returns the attributes passed at the initialize time
|
381
|
+
# Iterates thru the defined attributes and their values
|
370
382
|
#
|
371
|
-
# @
|
383
|
+
# @param blk [Proc] a block
|
384
|
+
# @yieldparam attribute [Symbol] the name of the attribute
|
385
|
+
# @yieldparam value [Object,nil] the value of the attribute
|
372
386
|
#
|
373
|
-
# @since
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
#
|
379
|
-
#
|
380
|
-
# include Lotus::Validations
|
387
|
+
# @since x.x.x
|
388
|
+
def each(&blk)
|
389
|
+
to_h.each(&blk)
|
390
|
+
end
|
391
|
+
|
392
|
+
# Returns a Hash with the defined attributes as symbolized keys, and their
|
393
|
+
# relative values.
|
381
394
|
#
|
382
|
-
#
|
383
|
-
# end
|
395
|
+
# @return [Hash]
|
384
396
|
#
|
385
|
-
#
|
386
|
-
|
387
|
-
|
397
|
+
# @since x.x.x
|
398
|
+
def to_h
|
399
|
+
@attributes.dup
|
400
|
+
end
|
388
401
|
|
389
402
|
private
|
390
|
-
#
|
403
|
+
# The set of user defined attributes.
|
404
|
+
#
|
405
|
+
# @since x.x.x
|
391
406
|
# @api private
|
392
407
|
#
|
393
408
|
# @see Lotus::Validations::ClassMethods#attributes
|
394
|
-
def
|
409
|
+
def defined_attributes
|
395
410
|
self.class.__send__(:attributes)
|
396
411
|
end
|
397
412
|
end
|
@@ -11,44 +11,59 @@ end
|
|
11
11
|
|
12
12
|
module Lotus
|
13
13
|
module Validations
|
14
|
-
#
|
14
|
+
# A validable attribute
|
15
15
|
#
|
16
16
|
# @since 0.1.0
|
17
17
|
# @api private
|
18
|
-
class
|
18
|
+
class Attribute
|
19
19
|
# Attribute naming convention for "confirmation" validation
|
20
20
|
#
|
21
|
-
# @see Lotus::Validations::
|
21
|
+
# @see Lotus::Validations::Attribute#confirmation
|
22
22
|
#
|
23
|
-
# @since
|
23
|
+
# @since x.x.x
|
24
24
|
# @api private
|
25
25
|
CONFIRMATION_TEMPLATE = '%{name}_confirmation'.freeze
|
26
26
|
|
27
|
-
#
|
27
|
+
# Instantiate an attribute
|
28
28
|
#
|
29
29
|
# @param validator [Lotus::Validations] an object which included
|
30
30
|
# Lotus::Validations module
|
31
31
|
# @param name [Symbol] the name of the attribute
|
32
32
|
# @param options [Hash] the set of validations for the attribute
|
33
33
|
#
|
34
|
-
# @since
|
34
|
+
# @since x.x.x
|
35
35
|
# @api private
|
36
|
-
def initialize(validator, name, options)
|
37
|
-
|
38
|
-
|
36
|
+
# def initialize(validator, name, options)
|
37
|
+
# @validator, @name, @options = validator, name, options
|
38
|
+
# @value = _attribute(@name)
|
39
|
+
# end
|
40
|
+
def initialize(attributes, name, value, validations)
|
41
|
+
@attributes = attributes
|
42
|
+
@name = name
|
43
|
+
@value = value
|
44
|
+
@validations = validations
|
45
|
+
@errors = []
|
39
46
|
end
|
40
47
|
|
41
|
-
# Validate the attribute
|
42
|
-
#
|
43
|
-
# @return [void]
|
44
|
-
#
|
45
|
-
# @since 0.1.0
|
46
48
|
# @api private
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
# @since x.x.x
|
50
|
+
def validate
|
51
|
+
_with_cleared_errors do
|
52
|
+
presence
|
53
|
+
acceptance
|
50
54
|
|
51
|
-
|
55
|
+
_run_validations
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
# @since x.x.x
|
61
|
+
def value
|
62
|
+
if (coercer = @validations[:type])
|
63
|
+
Lotus::Validations::Coercions.coerce(coercer, @value)
|
64
|
+
else
|
65
|
+
@value
|
66
|
+
end
|
52
67
|
end
|
53
68
|
|
54
69
|
private
|
@@ -59,9 +74,9 @@ module Lotus
|
|
59
74
|
# Empty strings and enumerables are an example.
|
60
75
|
#
|
61
76
|
# @see Lotus::Validations::ClassMethods#attribute
|
62
|
-
# @see Lotus::Validations::
|
77
|
+
# @see Lotus::Validations::Attribute#nil_value?
|
63
78
|
#
|
64
|
-
# @since
|
79
|
+
# @since x.x.x
|
65
80
|
# @api private
|
66
81
|
def presence
|
67
82
|
_validate(__method__) { !blank_value? }
|
@@ -77,7 +92,7 @@ module Lotus
|
|
77
92
|
# @see Lotus::Validations::ClassMethods#attribute
|
78
93
|
# @see http://www.rubydoc.info/gems/lotus-utils/Lotus/Utils/Kernel#Boolean-class_method
|
79
94
|
#
|
80
|
-
# @since
|
95
|
+
# @since x.x.x
|
81
96
|
# @api private
|
82
97
|
def acceptance
|
83
98
|
_validate(__method__) { Lotus::Utils::Kernel.Boolean(@value) }
|
@@ -90,7 +105,7 @@ module Lotus
|
|
90
105
|
#
|
91
106
|
# @see Lotus::Validations::ClassMethods#attribute
|
92
107
|
#
|
93
|
-
# @since
|
108
|
+
# @since x.x.x
|
94
109
|
# @api private
|
95
110
|
def format
|
96
111
|
_validate(__method__) {|matcher| @value.to_s.match(matcher) }
|
@@ -102,7 +117,7 @@ module Lotus
|
|
102
117
|
#
|
103
118
|
# @see Lotus::Validations::ClassMethods#attribute
|
104
119
|
#
|
105
|
-
# @since
|
120
|
+
# @since x.x.x
|
106
121
|
# @api private
|
107
122
|
def inclusion
|
108
123
|
_validate(__method__) {|collection| collection.include?(@value) }
|
@@ -114,7 +129,7 @@ module Lotus
|
|
114
129
|
#
|
115
130
|
# @see Lotus::Validations::ClassMethods#attribute
|
116
131
|
#
|
117
|
-
# @since
|
132
|
+
# @since x.x.x
|
118
133
|
# @api private
|
119
134
|
def exclusion
|
120
135
|
_validate(__method__) {|collection| !collection.include?(@value) }
|
@@ -126,9 +141,9 @@ module Lotus
|
|
126
141
|
# `:password_confirmation` has the same value.
|
127
142
|
#
|
128
143
|
# @see Lotus::Validations::ClassMethods#attribute
|
129
|
-
# @see Lotus::Validations::
|
144
|
+
# @see Lotus::Validations::Attribute::CONFIRMATION_TEMPLATE
|
130
145
|
#
|
131
|
-
# @since
|
146
|
+
# @since x.x.x
|
132
147
|
# @api private
|
133
148
|
def confirmation
|
134
149
|
_validate(__method__) do
|
@@ -165,7 +180,7 @@ module Lotus
|
|
165
180
|
#
|
166
181
|
# @see Lotus::Validations::ClassMethods#attribute
|
167
182
|
#
|
168
|
-
# @since
|
183
|
+
# @since x.x.x
|
169
184
|
# @api private
|
170
185
|
def size
|
171
186
|
_validate(__method__) do |validator|
|
@@ -201,25 +216,23 @@ module Lotus
|
|
201
216
|
# purposes. The only limitation is that the constructor should have
|
202
217
|
# **arity of 1**.
|
203
218
|
#
|
204
|
-
# @raise [TypeError] if the coercion fails
|
205
219
|
# @raise [ArgumentError] if the custom coercer's `#initialize` has a wrong arity.
|
206
220
|
#
|
207
221
|
# @see Lotus::Validations::ClassMethods#attribute
|
208
222
|
# @see Lotus::Validations::Coercions
|
209
223
|
#
|
210
|
-
# @since
|
224
|
+
# @since x.x.x
|
211
225
|
# @api private
|
212
226
|
def coerce
|
213
227
|
_validate(:type) do |coercer|
|
214
228
|
@value = Lotus::Validations::Coercions.coerce(coercer, @value)
|
215
|
-
_attributes[@name] = @value
|
216
229
|
true
|
217
230
|
end
|
218
231
|
end
|
219
232
|
|
220
233
|
# Checks if the value is `nil`.
|
221
234
|
#
|
222
|
-
# @since
|
235
|
+
# @since x.x.x
|
223
236
|
# @api private
|
224
237
|
def nil_value?
|
225
238
|
@value.nil?
|
@@ -229,9 +242,9 @@ module Lotus
|
|
229
242
|
|
230
243
|
# Checks if the value is "blank".
|
231
244
|
#
|
232
|
-
# @see Lotus::Validations::
|
245
|
+
# @see Lotus::Validations::Attribute#presence
|
233
246
|
#
|
234
|
-
# @since
|
247
|
+
# @since x.x.x
|
235
248
|
# @api private
|
236
249
|
def blank_value?
|
237
250
|
nil_value? || (@value.respond_to?(:empty?) && @value.empty?)
|
@@ -239,7 +252,7 @@ module Lotus
|
|
239
252
|
|
240
253
|
# Run the defined validations
|
241
254
|
#
|
242
|
-
# @since
|
255
|
+
# @since x.x.x
|
243
256
|
# @api private
|
244
257
|
def _run_validations
|
245
258
|
return if skip?
|
@@ -252,27 +265,29 @@ module Lotus
|
|
252
265
|
confirmation
|
253
266
|
end
|
254
267
|
|
255
|
-
# Reads an attribute from the validator.
|
256
|
-
#
|
257
|
-
# @since 0.1.0
|
258
268
|
# @api private
|
259
|
-
|
260
|
-
|
269
|
+
# @since x.x.x
|
270
|
+
def _with_cleared_errors
|
271
|
+
@errors.clear
|
272
|
+
yield
|
273
|
+
@errors.dup.tap {|_| @errors.clear }
|
261
274
|
end
|
262
275
|
|
263
|
-
#
|
276
|
+
# Reads an attribute from the validator.
|
277
|
+
#
|
278
|
+
# @since x.x.x
|
264
279
|
# @api private
|
265
|
-
def
|
266
|
-
@
|
280
|
+
def _attribute(name = @name)
|
281
|
+
@attributes[name.to_sym]
|
267
282
|
end
|
268
283
|
|
269
284
|
# Run a single validation and collects the results.
|
270
285
|
#
|
271
|
-
# @since
|
286
|
+
# @since x.x.x
|
272
287
|
# @api private
|
273
288
|
def _validate(validation)
|
274
|
-
if (validator = @
|
275
|
-
@
|
289
|
+
if (validator = @validations[validation]) && !(yield validator)
|
290
|
+
@errors.push(Error.new(@name, validation, @validations.fetch(validation), @value))
|
276
291
|
end
|
277
292
|
end
|
278
293
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class AttributeSet
|
2
|
+
VALIDATIONS = [:presence, :acceptance, :format, :inclusion, :exclusion, :confirmation, :size, :type].freeze
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@attributes = Hash.new {|h,k| h[k] = {} }
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(name, options)
|
9
|
+
@attributes[name.to_sym].merge!(
|
10
|
+
validate_options!(name, options)
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(&blk)
|
15
|
+
@attributes.each(&blk)
|
16
|
+
end
|
17
|
+
|
18
|
+
def iterate(attributes, &blk)
|
19
|
+
if @attributes.any?
|
20
|
+
@attributes.each(&blk)
|
21
|
+
else
|
22
|
+
attributes.each do |name, _|
|
23
|
+
blk.call(name, {})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
# Checks at the loading time if the user defined validations are recognized
|
30
|
+
#
|
31
|
+
# @param name [Symbol] the attribute name
|
32
|
+
# @param options [Hash] the set of validations associated with the given attribute
|
33
|
+
#
|
34
|
+
# @raise [ArgumentError] if at least one of the validations are not
|
35
|
+
# recognized
|
36
|
+
#
|
37
|
+
# @since x.x.x
|
38
|
+
# @api private
|
39
|
+
def validate_options!(name, options)
|
40
|
+
if (unknown = (options.keys - VALIDATIONS)) && unknown.any?
|
41
|
+
raise ArgumentError.new(%(Unknown validation(s): #{ unknown.join ', ' } for "#{ name }" attribute))
|
42
|
+
end
|
43
|
+
|
44
|
+
# FIXME remove
|
45
|
+
if options[:confirmation]
|
46
|
+
add(:"#{ name }_confirmation", {})
|
47
|
+
end
|
48
|
+
|
49
|
+
options
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Validations
|
3
|
+
class Attributes
|
4
|
+
def initialize(definitions, attributes)
|
5
|
+
attributes = attributes.to_h
|
6
|
+
|
7
|
+
@attributes = Utils::Hash.new.tap do |result|
|
8
|
+
definitions.iterate(attributes) do |name, validations|
|
9
|
+
value = attributes[name]
|
10
|
+
value = attributes[name.to_s] if value.nil?
|
11
|
+
|
12
|
+
result[name] = Attribute.new(attributes, name, value, validations)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(name)
|
18
|
+
(attr = @attributes[name]) and attr.value
|
19
|
+
end
|
20
|
+
|
21
|
+
def dup
|
22
|
+
Utils::Hash.new(to_h).deep_dup
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&blk)
|
26
|
+
@attributes.each(&blk)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
::Hash.new.tap do |result|
|
31
|
+
each do |name, _|
|
32
|
+
result[name] = get(name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -13,14 +13,15 @@ module Lotus
|
|
13
13
|
# @param values [Array] of objects to be coerced
|
14
14
|
# @param blk [Proc] an optional block to pass to the custom coercer
|
15
15
|
#
|
16
|
-
# @
|
16
|
+
# @return [Object,nil] The result of the coercion, if possible
|
17
|
+
#
|
17
18
|
# @raise [ArgumentError] if the custom coercer's `#initialize` has a wrong arity.
|
18
19
|
#
|
19
20
|
# @since 0.1.0
|
20
21
|
# @api private
|
21
22
|
def self.coerce(coercer, *values, &blk)
|
22
23
|
if ::Lotus::Utils::Kernel.respond_to?(coercer.to_s)
|
23
|
-
::Lotus::Utils::Kernel.__send__(coercer.to_s, *values, &blk)
|
24
|
+
::Lotus::Utils::Kernel.__send__(coercer.to_s, *values, &blk) rescue nil
|
24
25
|
else
|
25
26
|
coercer.new(*values, &blk)
|
26
27
|
end
|
@@ -80,10 +80,8 @@ module Lotus
|
|
80
80
|
#
|
81
81
|
# @since 0.1.0
|
82
82
|
# @api private
|
83
|
-
def add(attribute,
|
84
|
-
@errors[attribute].push(
|
85
|
-
Error.new(attribute, validation, expected, actual)
|
86
|
-
)
|
83
|
+
def add(attribute, *errors)
|
84
|
+
@errors[attribute].push(*errors) if errors.any?
|
87
85
|
end
|
88
86
|
|
89
87
|
# Return the errors for the given attribute
|
data/lotus-validations.gemspec
CHANGED
@@ -13,13 +13,13 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = 'http://lotusrb.org'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files -- lib/* LICENSE.md README.md lotus-validations.gemspec`.split($/)
|
16
|
+
spec.files = `git ls-files -- lib/* LICENSE.md README.md CHANGELOG.md lotus-validations.gemspec`.split($/)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
spec.required_ruby_version = '>= 2.0.0'
|
21
21
|
|
22
|
-
spec.add_dependency 'lotus-utils', '~> 0.3'
|
22
|
+
spec.add_dependency 'lotus-utils', '~> 0.3', '>= 0.3.1'
|
23
23
|
|
24
24
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
25
25
|
spec.add_development_dependency 'minitest', '~> 5'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lotus-validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lotus-utils
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.3'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.3.1
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - "~>"
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0.3'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.3.1
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: bundler
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,11 +79,14 @@ executables: []
|
|
73
79
|
extensions: []
|
74
80
|
extra_rdoc_files: []
|
75
81
|
files:
|
82
|
+
- CHANGELOG.md
|
76
83
|
- LICENSE.md
|
77
84
|
- README.md
|
78
85
|
- lib/lotus-validations.rb
|
79
86
|
- lib/lotus/validations.rb
|
80
|
-
- lib/lotus/validations/
|
87
|
+
- lib/lotus/validations/attribute.rb
|
88
|
+
- lib/lotus/validations/attribute_set.rb
|
89
|
+
- lib/lotus/validations/attributes.rb
|
81
90
|
- lib/lotus/validations/coercions.rb
|
82
91
|
- lib/lotus/validations/error.rb
|
83
92
|
- lib/lotus/validations/errors.rb
|