lotus-validations 0.1.0 → 0.2.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 +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
|