lotus-validations 0.2.1 → 0.2.2
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 +5 -0
- data/README.md +37 -5
- data/lib/lotus/validations/attribute.rb +8 -71
- data/lib/lotus/validations/attribute_definer.rb +354 -0
- data/lib/lotus/validations/blank_value_checker.rb +45 -0
- data/lib/lotus/validations/coercions.rb +4 -4
- data/lib/lotus/validations/validation_set.rb +73 -0
- data/lib/lotus/validations/validator.rb +28 -0
- data/lib/lotus/validations/version.rb +1 -1
- data/lib/lotus/validations.rb +77 -239
- data/lotus-validations.gemspec +3 -3
- metadata +11 -7
- data/lib/lotus/validations/attribute_set.rb +0 -51
- data/lib/lotus/validations/attributes.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0249c7c704d709f9579693a8f8b8faac3c1ca338
|
4
|
+
data.tar.gz: e2913b58194002b58ec6da05154982e46d30efd5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e82fe5c215943d1fdfd11068c1b5639dcec94062a1e1cce5dafee5ee643e09dde7b05b826f1c32d7d9c10e33a0b618587cdae1a393c21f0361388f8162798afa
|
7
|
+
data.tar.gz: b92988e71b73a27e7319acf7957e001042035ce9091c3f2a1e55d83f7f9d4afb45f6c41c9742d1ba663e4eca107977c714685e53577143b7baf5e51bc11ad4b7
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
# Lotus::Validations
|
2
2
|
Validations mixin for Ruby objects
|
3
3
|
|
4
|
+
## v0.2.2 - 2015-01-08
|
5
|
+
### Added
|
6
|
+
- [Steve Hodgkiss] Introduced `Validations.validates`. It defines validations, for already existing attributes.
|
7
|
+
|
4
8
|
## v0.2.1 - 2014-12-23
|
5
9
|
### Added
|
6
10
|
- [Luca Guidi] Introduced `Validations::Errors#to_h` and `to_a`
|
7
11
|
- [Luca Guidi] Introduced `Validations::Errors#any?`
|
12
|
+
- [Luca Guidi] Official support for Ruby 2.2
|
8
13
|
|
9
14
|
### Fixed
|
10
15
|
- [Satoshi Amemiya] Made `Validations#valid?` idempotent
|
data/README.md
CHANGED
@@ -57,14 +57,46 @@ require 'lotus/validations'
|
|
57
57
|
class Person
|
58
58
|
include Lotus::Validations
|
59
59
|
|
60
|
-
attribute :name
|
60
|
+
attribute :name, presence: true
|
61
|
+
attribute :email, presence: true
|
61
62
|
end
|
62
63
|
|
63
|
-
person = Person.new(name: 'Luca', age: 32)
|
64
|
-
person.name
|
65
|
-
person.
|
64
|
+
person = Person.new(name: 'Luca', email: 'me@example.org', age: 32)
|
65
|
+
person.name # => "Luca"
|
66
|
+
person.email # => "me@example.org"
|
67
|
+
person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
|
66
68
|
```
|
67
69
|
|
70
|
+
### Validations
|
71
|
+
|
72
|
+
If you prefer Lotus::Validations to **only define validations**, but **not attributes**,
|
73
|
+
you can use the following alternative syntax.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
require 'lotus/validations'
|
77
|
+
|
78
|
+
class Person
|
79
|
+
include Lotus::Validations
|
80
|
+
attr_accessor :name, :email
|
81
|
+
|
82
|
+
# Custom initializer
|
83
|
+
def initialize(attributes = {})
|
84
|
+
@name, @email = attributes.values_at(:name, :email)
|
85
|
+
end
|
86
|
+
|
87
|
+
validates :name, presence: true
|
88
|
+
validates :email, presence: true
|
89
|
+
end
|
90
|
+
|
91
|
+
person = Person.new(name: 'Luca', email: 'me@example.org')
|
92
|
+
person.name # => "Luca"
|
93
|
+
person.email # => "me@example.org"
|
94
|
+
```
|
95
|
+
|
96
|
+
This is a bit more verbose, but offers a great level of flexibility for your
|
97
|
+
Ruby objects. It also allows to use Lotus::Validations in combination with
|
98
|
+
**other frameworks**.
|
99
|
+
|
68
100
|
### Coercions
|
69
101
|
|
70
102
|
If a Ruby class is passed to the `:type` option, the given value is coerced, accordingly.
|
@@ -129,7 +161,7 @@ end
|
|
129
161
|
person = Person.new(fav_number: '23', date: 'Oct 23, 2014')
|
130
162
|
person.valid?
|
131
163
|
|
132
|
-
person.fav_number # => 23
|
164
|
+
person.fav_number # => #<FavNumber:0x007ffc644bba00 @number="23">
|
133
165
|
person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
|
134
166
|
```
|
135
167
|
|
@@ -24,10 +24,6 @@ module Lotus
|
|
24
24
|
# @api private
|
25
25
|
CONFIRMATION_TEMPLATE = '%{name}_confirmation'.freeze
|
26
26
|
|
27
|
-
# @since 0.2.0
|
28
|
-
# @api private
|
29
|
-
BLANK_STRING_MATCHER = /\A[[:space:]]*\z/.freeze
|
30
|
-
|
31
27
|
# Instantiate an attribute
|
32
28
|
#
|
33
29
|
# @param attributes [Hash] a set of attributes and values coming from the
|
@@ -50,23 +46,13 @@ module Lotus
|
|
50
46
|
# @since 0.2.0
|
51
47
|
def validate
|
52
48
|
_with_cleared_errors do
|
53
|
-
presence
|
54
|
-
acceptance
|
55
|
-
|
56
49
|
_run_validations
|
57
50
|
end
|
58
51
|
end
|
59
52
|
|
60
53
|
# @api private
|
61
54
|
# @since 0.2.0
|
62
|
-
|
63
|
-
if (coercer = @validations[:type])
|
64
|
-
return nil if blank_value?
|
65
|
-
Lotus::Validations::Coercions.coerce(coercer, @value)
|
66
|
-
else
|
67
|
-
@value
|
68
|
-
end
|
69
|
-
end
|
55
|
+
attr_reader :value
|
70
56
|
|
71
57
|
private
|
72
58
|
# Validates presence of the value.
|
@@ -197,71 +183,20 @@ module Lotus
|
|
197
183
|
end
|
198
184
|
end
|
199
185
|
|
200
|
-
#
|
201
|
-
# Built in types are:
|
202
|
-
#
|
203
|
-
# * `Array`
|
204
|
-
# * `BigDecimal`
|
205
|
-
# * `Boolean`
|
206
|
-
# * `Date`
|
207
|
-
# * `DateTime`
|
208
|
-
# * `Float`
|
209
|
-
# * `Hash`
|
210
|
-
# * `Integer`
|
211
|
-
# * `Pathname`
|
212
|
-
# * `Set`
|
213
|
-
# * `String`
|
214
|
-
# * `Symbol`
|
215
|
-
# * `Time`
|
216
|
-
#
|
217
|
-
# If a user defined class is specified, it can be freely used for coercion
|
218
|
-
# purposes. The only limitation is that the constructor should have
|
219
|
-
# **arity of 1**.
|
220
|
-
#
|
221
|
-
# @raise [ArgumentError] if the custom coercer's `#initialize` has a wrong arity.
|
222
|
-
#
|
223
|
-
# @see Lotus::Validations::ClassMethods#attribute
|
224
|
-
# @see Lotus::Validations::Coercions
|
225
|
-
#
|
226
|
-
# @since 0.2.0
|
227
|
-
# @api private
|
228
|
-
def coerce
|
229
|
-
_validate(:type) do |coercer|
|
230
|
-
Lotus::Validations::Coercions.coerce(coercer, @value)
|
231
|
-
true
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
# Checks if the value is `nil`.
|
236
|
-
#
|
237
|
-
# @since 0.2.0
|
186
|
+
# @since 0.1.0
|
238
187
|
# @api private
|
239
|
-
def
|
188
|
+
def skip?
|
240
189
|
@value.nil?
|
241
190
|
end
|
242
191
|
|
243
|
-
alias_method :skip?, :nil_value?
|
244
|
-
|
245
192
|
# Checks if the value is "blank".
|
246
193
|
#
|
247
|
-
# @see Lotus::Validations::
|
194
|
+
# @see Lotus::Validations::BlankValueChecker
|
248
195
|
#
|
249
196
|
# @since 0.2.0
|
250
197
|
# @api private
|
251
198
|
def blank_value?
|
252
|
-
|
253
|
-
end
|
254
|
-
|
255
|
-
# @since 0.2.0
|
256
|
-
# @api private
|
257
|
-
def _blank_string?
|
258
|
-
(@value.respond_to?(:match) and @value.match(BLANK_STRING_MATCHER))
|
259
|
-
end
|
260
|
-
|
261
|
-
# @since 0.2.0
|
262
|
-
# @api private
|
263
|
-
def _empty_value?
|
264
|
-
(@value.respond_to?(:empty?) and @value.empty?)
|
199
|
+
BlankValueChecker.new(@value).blank_value?
|
265
200
|
end
|
266
201
|
|
267
202
|
# Run the defined validations
|
@@ -269,10 +204,12 @@ module Lotus
|
|
269
204
|
# @since 0.2.0
|
270
205
|
# @api private
|
271
206
|
def _run_validations
|
207
|
+
presence
|
208
|
+
acceptance
|
209
|
+
|
272
210
|
return if skip?
|
273
211
|
|
274
212
|
format
|
275
|
-
coerce
|
276
213
|
inclusion
|
277
214
|
exclusion
|
278
215
|
size
|
@@ -0,0 +1,354 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'lotus/utils/attributes'
|
3
|
+
|
4
|
+
module Lotus
|
5
|
+
module Validations
|
6
|
+
# Define attributes and their validations together
|
7
|
+
#
|
8
|
+
# @since 0.2.2
|
9
|
+
# @api private
|
10
|
+
module AttributeDefiner
|
11
|
+
# Override Ruby's hook for modules.
|
12
|
+
#
|
13
|
+
# @param base [Class] the target class
|
14
|
+
#
|
15
|
+
# @since 0.2.2
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
# @see http://www.ruby-doc.org/core/Module.html#method-i-included
|
19
|
+
def self.included(base)
|
20
|
+
base.extend ClassMethods
|
21
|
+
end
|
22
|
+
|
23
|
+
# @since 0.2.2
|
24
|
+
# @api private
|
25
|
+
module ClassMethods
|
26
|
+
# Override Ruby's hook for modules.
|
27
|
+
#
|
28
|
+
# @param base [Class] the target class
|
29
|
+
#
|
30
|
+
# @since 0.2.2
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
# @see http://www.ruby-doc.org/core/Module.html#method-i-extended
|
34
|
+
def included(base)
|
35
|
+
super
|
36
|
+
base.defined_attributes.merge(defined_attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Override Ruby's hook for modules.
|
40
|
+
#
|
41
|
+
# @param base [Class] the target class
|
42
|
+
#
|
43
|
+
# @since 0.2.2
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
# @see http://www.ruby-doc.org/core/Module.html#method-i-extended
|
47
|
+
def inherited(base)
|
48
|
+
super
|
49
|
+
base.defined_attributes.merge(defined_attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Define an attribute
|
53
|
+
#
|
54
|
+
# @param name [#to_sym] the name of the attribute
|
55
|
+
# @param options [Hash] optional set of validations
|
56
|
+
# @option options [Class] :type the Ruby type used to coerce the value
|
57
|
+
# @option options [TrueClass,FalseClass] :acceptance requires Ruby
|
58
|
+
# thruthiness of the value
|
59
|
+
# @option options [TrueClass,FalseClass] :confirmation requires the value
|
60
|
+
# to be confirmed twice
|
61
|
+
# @option options [#include?] :exclusion requires the value NOT be
|
62
|
+
# included in the given collection
|
63
|
+
# @option options [Regexp] :format requires value to match the given
|
64
|
+
# Regexp
|
65
|
+
# @option options [#include?] :inclusion requires the value BE included in
|
66
|
+
# the given collection
|
67
|
+
# @option options [TrueClass,FalseClass] :presence requires the value be
|
68
|
+
# included in the given collection
|
69
|
+
# @option options [Numeric,Range] :size requires value's to be equal or
|
70
|
+
# included by the given validator
|
71
|
+
#
|
72
|
+
# @raise [ArgumentError] if an unknown or mispelled validation is given
|
73
|
+
#
|
74
|
+
# @since 0.2.2
|
75
|
+
#
|
76
|
+
# @example Attributes
|
77
|
+
# require 'lotus/validations'
|
78
|
+
#
|
79
|
+
# class Person
|
80
|
+
# include Lotus::Validations
|
81
|
+
#
|
82
|
+
# attribute :name
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# person = Person.new(name: 'Luca', age: 32)
|
86
|
+
# person.name # => "Luca"
|
87
|
+
# person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
|
88
|
+
#
|
89
|
+
# @example Standard coercions
|
90
|
+
# require 'lotus/validations'
|
91
|
+
#
|
92
|
+
# class Person
|
93
|
+
# include Lotus::Validations
|
94
|
+
#
|
95
|
+
# attribute :fav_number, type: Integer
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# person = Person.new(fav_number: '23')
|
99
|
+
# person.valid?
|
100
|
+
#
|
101
|
+
# person.fav_number # => 23
|
102
|
+
#
|
103
|
+
# @example Custom coercions
|
104
|
+
# require 'lotus/validations'
|
105
|
+
#
|
106
|
+
# class FavNumber
|
107
|
+
# def initialize(number)
|
108
|
+
# @number = number
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# class BirthDate
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# class Person
|
116
|
+
# include Lotus::Validations
|
117
|
+
#
|
118
|
+
# attribute :fav_number, type: FavNumber
|
119
|
+
# attribute :date, type: BirthDate
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# person = Person.new(fav_number: '23', date: 'Oct 23, 2014')
|
123
|
+
# person.valid?
|
124
|
+
#
|
125
|
+
# person.fav_number # => 23
|
126
|
+
# person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
|
127
|
+
#
|
128
|
+
# @example Acceptance
|
129
|
+
# require 'lotus/validations'
|
130
|
+
#
|
131
|
+
# class Signup
|
132
|
+
# include Lotus::Validations
|
133
|
+
#
|
134
|
+
# attribute :terms_of_service, acceptance: true
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# signup = Signup.new(terms_of_service: '1')
|
138
|
+
# signup.valid? # => true
|
139
|
+
#
|
140
|
+
# signup = Signup.new(terms_of_service: '')
|
141
|
+
# signup.valid? # => false
|
142
|
+
#
|
143
|
+
# @example Confirmation
|
144
|
+
# require 'lotus/validations'
|
145
|
+
#
|
146
|
+
# class Signup
|
147
|
+
# include Lotus::Validations
|
148
|
+
#
|
149
|
+
# attribute :password, confirmation: true
|
150
|
+
# end
|
151
|
+
#
|
152
|
+
# signup = Signup.new(password: 'secret', password_confirmation: 'secret')
|
153
|
+
# signup.valid? # => true
|
154
|
+
#
|
155
|
+
# signup = Signup.new(password: 'secret', password_confirmation: 'x')
|
156
|
+
# signup.valid? # => false
|
157
|
+
#
|
158
|
+
# @example Exclusion
|
159
|
+
# require 'lotus/validations'
|
160
|
+
#
|
161
|
+
# class Signup
|
162
|
+
# include Lotus::Validations
|
163
|
+
#
|
164
|
+
# attribute :music, exclusion: ['pop']
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# signup = Signup.new(music: 'rock')
|
168
|
+
# signup.valid? # => true
|
169
|
+
#
|
170
|
+
# signup = Signup.new(music: 'pop')
|
171
|
+
# signup.valid? # => false
|
172
|
+
#
|
173
|
+
# @example Format
|
174
|
+
# require 'lotus/validations'
|
175
|
+
#
|
176
|
+
# class Signup
|
177
|
+
# include Lotus::Validations
|
178
|
+
#
|
179
|
+
# attribute :name, format: /\A[a-zA-Z]+\z/
|
180
|
+
# end
|
181
|
+
#
|
182
|
+
# signup = Signup.new(name: 'Luca')
|
183
|
+
# signup.valid? # => true
|
184
|
+
#
|
185
|
+
# signup = Signup.new(name: '23')
|
186
|
+
# signup.valid? # => false
|
187
|
+
#
|
188
|
+
# @example Inclusion
|
189
|
+
# require 'lotus/validations'
|
190
|
+
#
|
191
|
+
# class Signup
|
192
|
+
# include Lotus::Validations
|
193
|
+
#
|
194
|
+
# attribute :age, inclusion: 18..99
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# signup = Signup.new(age: 32)
|
198
|
+
# signup.valid? # => true
|
199
|
+
#
|
200
|
+
# signup = Signup.new(age: 17)
|
201
|
+
# signup.valid? # => false
|
202
|
+
#
|
203
|
+
# @example Presence
|
204
|
+
# require 'lotus/validations'
|
205
|
+
#
|
206
|
+
# class Signup
|
207
|
+
# include Lotus::Validations
|
208
|
+
#
|
209
|
+
# attribute :name, presence: true
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# signup = Signup.new(name: 'Luca')
|
213
|
+
# signup.valid? # => true
|
214
|
+
#
|
215
|
+
# signup = Signup.new(name: nil)
|
216
|
+
# signup.valid? # => false
|
217
|
+
#
|
218
|
+
# @example Size
|
219
|
+
# require 'lotus/validations'
|
220
|
+
#
|
221
|
+
# class Signup
|
222
|
+
# MEGABYTE = 1024 ** 2
|
223
|
+
# include Lotus::Validations
|
224
|
+
#
|
225
|
+
# attribute :ssn, size: 11 # exact match
|
226
|
+
# attribute :password, size: 8..64 # range
|
227
|
+
# attribute :avatar, size 1..(5 * MEGABYTE)
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# signup = Signup.new(password: 'a-very-long-password')
|
231
|
+
# signup.valid? # => true
|
232
|
+
#
|
233
|
+
# signup = Signup.new(password: 'short')
|
234
|
+
# signup.valid? # => false
|
235
|
+
def attribute(name, options = {})
|
236
|
+
define_attribute(name, options)
|
237
|
+
validates(name, options)
|
238
|
+
end
|
239
|
+
|
240
|
+
def defined_attributes
|
241
|
+
@defined_attributes ||= Set.new
|
242
|
+
end
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
# @since 0.2.2
|
247
|
+
# @api private
|
248
|
+
def define_attribute(name, options)
|
249
|
+
type = options.delete(:type)
|
250
|
+
define_accessor(name, type)
|
251
|
+
defined_attributes.add(name.to_s)
|
252
|
+
|
253
|
+
if options[:confirmation]
|
254
|
+
confirmation_accessor = "#{ name }_confirmation"
|
255
|
+
define_accessor(confirmation_accessor, type)
|
256
|
+
defined_attributes.add(confirmation_accessor)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# @since 0.2.2
|
261
|
+
# @api private
|
262
|
+
def define_accessor(name, type)
|
263
|
+
if type
|
264
|
+
define_reader(name)
|
265
|
+
define_coerced_writer(name, type)
|
266
|
+
else
|
267
|
+
define_reader(name)
|
268
|
+
define_writer(name)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# @since 0.2.2
|
273
|
+
# @api private
|
274
|
+
def define_coerced_writer(name, type)
|
275
|
+
define_method("#{ name }=") do |value|
|
276
|
+
@attributes.set(name, Lotus::Validations::Coercions.coerce(type, value))
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# @since 0.2.2
|
281
|
+
# @api private
|
282
|
+
def define_writer(name)
|
283
|
+
define_method("#{ name }=") do |value|
|
284
|
+
@attributes.set(name, value)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# @since 0.2.2
|
289
|
+
# @api private
|
290
|
+
def define_reader(name)
|
291
|
+
define_method(name) do
|
292
|
+
@attributes.get(name)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Create a new instance with the given attributes
|
298
|
+
#
|
299
|
+
# @param attributes [#to_h] an Hash like object which contains the
|
300
|
+
# attributes
|
301
|
+
#
|
302
|
+
# @since 0.2.2
|
303
|
+
#
|
304
|
+
# @example Initialize with Hash
|
305
|
+
# require 'lotus/validations'
|
306
|
+
#
|
307
|
+
# class Signup
|
308
|
+
# include Lotus::Validations
|
309
|
+
#
|
310
|
+
# attribute :name
|
311
|
+
# end
|
312
|
+
#
|
313
|
+
# signup = Signup.new(name: 'Luca')
|
314
|
+
#
|
315
|
+
# @example Initialize with Hash like
|
316
|
+
# require 'lotus/validations'
|
317
|
+
#
|
318
|
+
# class Params
|
319
|
+
# def initialize(attributes)
|
320
|
+
# @attributes = Hash[*attributes]
|
321
|
+
# end
|
322
|
+
#
|
323
|
+
# def to_h
|
324
|
+
# @attributes.to_h
|
325
|
+
# end
|
326
|
+
# end
|
327
|
+
#
|
328
|
+
# class Signup
|
329
|
+
# include Lotus::Validations
|
330
|
+
#
|
331
|
+
# attribute :name
|
332
|
+
# end
|
333
|
+
#
|
334
|
+
# params = Params.new([:name, 'Luca'])
|
335
|
+
# signup = Signup.new(params)
|
336
|
+
#
|
337
|
+
# signup.name # => "Luca"
|
338
|
+
def initialize(attributes)
|
339
|
+
@attributes ||= Utils::Attributes.new
|
340
|
+
|
341
|
+
attributes.to_h.each do |key, value|
|
342
|
+
public_send("#{ key }=", value) if assign_attribute?(key)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
private
|
347
|
+
# @since 0.2.2
|
348
|
+
# @api private
|
349
|
+
def assign_attribute?(attr)
|
350
|
+
self.class.defined_attributes.include?(attr.to_s)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Validations
|
3
|
+
# @since 0.2.2
|
4
|
+
# @api private
|
5
|
+
class BlankValueChecker
|
6
|
+
# @since 0.2.2
|
7
|
+
# @api private
|
8
|
+
BLANK_STRING_MATCHER = /\A[[:space:]]*\z/.freeze
|
9
|
+
|
10
|
+
def initialize(value)
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
# Checks if the value is "blank".
|
15
|
+
#
|
16
|
+
# @since 0.2.2
|
17
|
+
# @api private
|
18
|
+
def blank_value?
|
19
|
+
_nil_value? || _blank_string? || _empty_value?
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Checks if the value is `nil`.
|
25
|
+
#
|
26
|
+
# @since 0.2.2
|
27
|
+
# @api private
|
28
|
+
def _nil_value?
|
29
|
+
@value.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
# @since 0.2.2
|
33
|
+
# @api private
|
34
|
+
def _blank_string?
|
35
|
+
(@value.respond_to?(:match) and @value.match(BLANK_STRING_MATCHER))
|
36
|
+
end
|
37
|
+
|
38
|
+
# @since 0.2.2
|
39
|
+
# @api private
|
40
|
+
def _empty_value?
|
41
|
+
(@value.respond_to?(:empty?) and @value.empty?)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -10,7 +10,7 @@ module Lotus
|
|
10
10
|
# Coerces the given values with the given type
|
11
11
|
#
|
12
12
|
# @param coercer [Class] the type
|
13
|
-
# @param
|
13
|
+
# @param value [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
|
@@ -19,11 +19,11 @@ module Lotus
|
|
19
19
|
#
|
20
20
|
# @since 0.1.0
|
21
21
|
# @api private
|
22
|
-
def self.coerce(coercer,
|
22
|
+
def self.coerce(coercer, value, &blk)
|
23
23
|
if ::Lotus::Utils::Kernel.respond_to?(coercer.to_s)
|
24
|
-
::Lotus::Utils::Kernel.__send__(coercer.to_s,
|
24
|
+
::Lotus::Utils::Kernel.__send__(coercer.to_s, value, &blk) rescue nil
|
25
25
|
else
|
26
|
-
coercer.new(
|
26
|
+
coercer.new(value, &blk)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Validations
|
3
|
+
# A set of validations defined on an object
|
4
|
+
#
|
5
|
+
# @since 0.2.2
|
6
|
+
# @api private
|
7
|
+
class ValidationSet
|
8
|
+
# Allowed validations
|
9
|
+
#
|
10
|
+
# @since 0.2.2
|
11
|
+
# @api private
|
12
|
+
VALIDATIONS = [
|
13
|
+
:presence,
|
14
|
+
:acceptance,
|
15
|
+
:format,
|
16
|
+
:inclusion,
|
17
|
+
:exclusion,
|
18
|
+
:confirmation,
|
19
|
+
:size
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
# @since 0.2.2
|
23
|
+
# @api private
|
24
|
+
def initialize
|
25
|
+
@validations = Hash.new {|h,k| h[k] = {} }
|
26
|
+
end
|
27
|
+
|
28
|
+
# @since 0.2.2
|
29
|
+
# @api private
|
30
|
+
def add(name, options)
|
31
|
+
@validations[name.to_sym].merge!(
|
32
|
+
validate_options!(name, options)
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @since 0.2.2
|
37
|
+
# @api private
|
38
|
+
def each(&blk)
|
39
|
+
@validations.each(&blk)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @since 0.2.2
|
43
|
+
# @api private
|
44
|
+
def each_key(&blk)
|
45
|
+
@validations.each_key(&blk)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
# Checks at the loading time if the user defined validations are recognized
|
50
|
+
#
|
51
|
+
# @param name [Symbol] the attribute name
|
52
|
+
# @param options [Hash] the set of validations associated with the given attribute
|
53
|
+
#
|
54
|
+
# @raise [ArgumentError] if at least one of the validations are not
|
55
|
+
# recognized
|
56
|
+
#
|
57
|
+
# @since 0.2.2
|
58
|
+
# @api private
|
59
|
+
def validate_options!(name, options)
|
60
|
+
if (unknown = (options.keys - VALIDATIONS)) && unknown.any?
|
61
|
+
raise ArgumentError.new(%(Unknown validation(s): #{ unknown.join ', ' } for "#{ name }" attribute))
|
62
|
+
end
|
63
|
+
|
64
|
+
# FIXME remove
|
65
|
+
if options[:confirmation]
|
66
|
+
add(:"#{ name }_confirmation", {})
|
67
|
+
end
|
68
|
+
|
69
|
+
options
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Validations
|
3
|
+
# Validate given validations and return a set of errors
|
4
|
+
#
|
5
|
+
# @since 0.2.2
|
6
|
+
# @api private
|
7
|
+
class Validator
|
8
|
+
def initialize(validation_set, attributes)
|
9
|
+
@validation_set = validation_set
|
10
|
+
@attributes = attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
# @since 0.2.2
|
14
|
+
# @api private
|
15
|
+
def validate
|
16
|
+
Errors.new.tap do |errors|
|
17
|
+
@validation_set.each do |name, validations|
|
18
|
+
value = @attributes[name]
|
19
|
+
value = @attributes[name.to_s] if value.nil?
|
20
|
+
|
21
|
+
attribute = Attribute.new(@attributes, name, value, validations)
|
22
|
+
errors.add name, *attribute.validate
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/lotus/validations.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'lotus/utils/hash'
|
2
2
|
require 'lotus/validations/version'
|
3
|
-
require 'lotus/validations/
|
4
|
-
require 'lotus/validations/
|
3
|
+
require 'lotus/validations/blank_value_checker'
|
4
|
+
require 'lotus/validations/attribute_definer'
|
5
|
+
require 'lotus/validations/validation_set'
|
6
|
+
require 'lotus/validations/validator'
|
5
7
|
require 'lotus/validations/attribute'
|
6
8
|
require 'lotus/validations/errors'
|
7
9
|
|
@@ -19,16 +21,34 @@ module Lotus
|
|
19
21
|
#
|
20
22
|
# @see http://www.ruby-doc.org/core/Module.html#method-i-included
|
21
23
|
def self.included(base)
|
22
|
-
base.
|
24
|
+
base.class_eval do
|
25
|
+
extend ClassMethods
|
26
|
+
include AttributeDefiner
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
# Validations DSL
|
26
31
|
#
|
27
32
|
# @since 0.1.0
|
28
33
|
module ClassMethods
|
34
|
+
# Override Ruby's hook for class inheritance. When a class includes
|
35
|
+
# Lotus::Validations and it is subclassed, this passes
|
36
|
+
# the attributes from the superclass to the subclass.
|
37
|
+
#
|
38
|
+
# @param base [Class] the target action
|
39
|
+
#
|
40
|
+
# @since 0.2.2
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
# @see http://www.ruby-doc.org/core/Class.html#method-i-inherited
|
44
|
+
def inherited(base)
|
45
|
+
transfer_validations_to_base(base)
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
29
49
|
# Override Ruby's hook for modules. When a module includes
|
30
50
|
# Lotus::Validations and it is included in a class or module, this passes
|
31
|
-
# the
|
51
|
+
# the validations from the module to the base.
|
32
52
|
#
|
33
53
|
# @param base [Class] the target action
|
34
54
|
#
|
@@ -60,167 +80,31 @@ module Lotus
|
|
60
80
|
include Lotus::Validations
|
61
81
|
end
|
62
82
|
|
63
|
-
|
64
|
-
|
65
|
-
|
83
|
+
super
|
84
|
+
|
85
|
+
transfer_validations_to_base(base)
|
66
86
|
end
|
67
87
|
|
68
|
-
# Define an attribute
|
88
|
+
# Define a validation for an existing attribute
|
69
89
|
#
|
70
90
|
# @param name [#to_sym] the name of the attribute
|
71
|
-
# @param options [Hash]
|
72
|
-
# @option options [Class] :type the Ruby type used to coerce the value
|
73
|
-
# @option options [TrueClass,FalseClass] :acceptance requires Ruby
|
74
|
-
# thruthiness of the value
|
75
|
-
# @option options [TrueClass,FalseClass] :confirmation requires the value
|
76
|
-
# to be confirmed twice
|
77
|
-
# @option options [#include?] :exclusion requires the value NOT be
|
78
|
-
# included in the given collection
|
79
|
-
# @option options [Regexp] :format requires value to match the given
|
80
|
-
# Regexp
|
81
|
-
# @option options [#include?] :inclusion requires the value BE included in
|
82
|
-
# the given collection
|
83
|
-
# @option options [TrueClass,FalseClass] :presence requires the value be
|
84
|
-
# included in the given collection
|
85
|
-
# @option options [Numeric,Range] :size requires value's to be equal or
|
86
|
-
# included by the given validator
|
87
|
-
#
|
88
|
-
# @raise [ArgumentError] if an unknown or mispelled validation is given
|
89
|
-
#
|
90
|
-
# @example Attributes
|
91
|
-
# require 'lotus/validations'
|
92
|
-
#
|
93
|
-
# class Person
|
94
|
-
# include Lotus::Validations
|
95
|
-
#
|
96
|
-
# attribute :name
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# person = Person.new(name: 'Luca', age: 32)
|
100
|
-
# person.name # => "Luca"
|
101
|
-
# person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
|
102
|
-
#
|
103
|
-
# @example Standard coercions
|
104
|
-
# require 'lotus/validations'
|
105
|
-
#
|
106
|
-
# class Person
|
107
|
-
# include Lotus::Validations
|
108
|
-
#
|
109
|
-
# attribute :fav_number, type: Integer
|
110
|
-
# end
|
111
|
-
#
|
112
|
-
# person = Person.new(fav_number: '23')
|
113
|
-
# person.valid?
|
114
|
-
#
|
115
|
-
# person.fav_number # => 23
|
116
|
-
#
|
117
|
-
# @example Custom coercions
|
118
|
-
# require 'lotus/validations'
|
119
|
-
#
|
120
|
-
# class FavNumber
|
121
|
-
# def initialize(number)
|
122
|
-
# @number = number
|
123
|
-
# end
|
124
|
-
# end
|
125
|
-
#
|
126
|
-
# class BirthDate
|
127
|
-
# end
|
128
|
-
#
|
129
|
-
# class Person
|
130
|
-
# include Lotus::Validations
|
131
|
-
#
|
132
|
-
# attribute :fav_number, type: FavNumber
|
133
|
-
# attribute :date, type: BirthDate
|
134
|
-
# end
|
91
|
+
# @param options [Hash] set of validations
|
135
92
|
#
|
136
|
-
#
|
137
|
-
# person.valid?
|
93
|
+
# @see Lotus::Validations::ClassMethods#validations
|
138
94
|
#
|
139
|
-
#
|
140
|
-
# person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
|
141
|
-
#
|
142
|
-
# @example Acceptance
|
143
|
-
# require 'lotus/validations'
|
144
|
-
#
|
145
|
-
# class Signup
|
146
|
-
# include Lotus::Validations
|
147
|
-
#
|
148
|
-
# attribute :terms_of_service, acceptance: true
|
149
|
-
# end
|
150
|
-
#
|
151
|
-
# signup = Signup.new(terms_of_service: '1')
|
152
|
-
# signup.valid? # => true
|
153
|
-
#
|
154
|
-
# signup = Signup.new(terms_of_service: '')
|
155
|
-
# signup.valid? # => false
|
156
|
-
#
|
157
|
-
# @example Confirmation
|
158
|
-
# require 'lotus/validations'
|
159
|
-
#
|
160
|
-
# class Signup
|
161
|
-
# include Lotus::Validations
|
162
|
-
#
|
163
|
-
# attribute :password, confirmation: true
|
164
|
-
# end
|
165
|
-
#
|
166
|
-
# signup = Signup.new(password: 'secret', password_confirmation: 'secret')
|
167
|
-
# signup.valid? # => true
|
168
|
-
#
|
169
|
-
# signup = Signup.new(password: 'secret', password_confirmation: 'x')
|
170
|
-
# signup.valid? # => false
|
171
|
-
#
|
172
|
-
# @example Exclusion
|
173
|
-
# require 'lotus/validations'
|
174
|
-
#
|
175
|
-
# class Signup
|
176
|
-
# include Lotus::Validations
|
177
|
-
#
|
178
|
-
# attribute :music, exclusion: ['pop']
|
179
|
-
# end
|
180
|
-
#
|
181
|
-
# signup = Signup.new(music: 'rock')
|
182
|
-
# signup.valid? # => true
|
183
|
-
#
|
184
|
-
# signup = Signup.new(music: 'pop')
|
185
|
-
# signup.valid? # => false
|
186
|
-
#
|
187
|
-
# @example Format
|
188
|
-
# require 'lotus/validations'
|
189
|
-
#
|
190
|
-
# class Signup
|
191
|
-
# include Lotus::Validations
|
192
|
-
#
|
193
|
-
# attribute :name, format: /\A[a-zA-Z]+\z/
|
194
|
-
# end
|
195
|
-
#
|
196
|
-
# signup = Signup.new(name: 'Luca')
|
197
|
-
# signup.valid? # => true
|
198
|
-
#
|
199
|
-
# signup = Signup.new(name: '23')
|
200
|
-
# signup.valid? # => false
|
201
|
-
#
|
202
|
-
# @example Inclusion
|
95
|
+
# @example Presence
|
203
96
|
# require 'lotus/validations'
|
204
97
|
#
|
205
98
|
# class Signup
|
206
99
|
# include Lotus::Validations
|
207
100
|
#
|
208
|
-
#
|
209
|
-
#
|
210
|
-
#
|
211
|
-
# signup = Signup.new(age: 32)
|
212
|
-
# signup.valid? # => true
|
213
|
-
#
|
214
|
-
# signup = Signup.new(age: 17)
|
215
|
-
# signup.valid? # => false
|
101
|
+
# def initialize(attributes = {})
|
102
|
+
# @name = attributes.fetch(:name)
|
103
|
+
# end
|
216
104
|
#
|
217
|
-
#
|
218
|
-
# require 'lotus/validations'
|
105
|
+
# attr_accessor :name
|
219
106
|
#
|
220
|
-
#
|
221
|
-
# include Lotus::Validations
|
222
|
-
#
|
223
|
-
# attribute :name, presence: true
|
107
|
+
# validates :name, presence: true
|
224
108
|
# end
|
225
109
|
#
|
226
110
|
# signup = Signup.new(name: 'Luca')
|
@@ -228,43 +112,32 @@ module Lotus
|
|
228
112
|
#
|
229
113
|
# signup = Signup.new(name: nil)
|
230
114
|
# signup.valid? # => false
|
115
|
+
def validates(name, options)
|
116
|
+
validations.add(name, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set of user defined validations
|
231
120
|
#
|
232
|
-
# @
|
233
|
-
# require 'lotus/validations'
|
234
|
-
#
|
235
|
-
# class Signup
|
236
|
-
# MEGABYTE = 1024 ** 2
|
237
|
-
# include Lotus::Validations
|
238
|
-
#
|
239
|
-
# attribute :ssn, size: 11 # exact match
|
240
|
-
# attribute :password, size: 8..64 # range
|
241
|
-
# attribute :avatar, size 1..(5 * MEGABYTE)
|
242
|
-
# end
|
243
|
-
#
|
244
|
-
# signup = Signup.new(password: 'a-very-long-password')
|
245
|
-
# signup.valid? # => true
|
121
|
+
# @return [Hash]
|
246
122
|
#
|
247
|
-
#
|
248
|
-
#
|
249
|
-
def
|
250
|
-
|
251
|
-
|
252
|
-
class_eval %{
|
253
|
-
def #{ name }
|
254
|
-
@attributes.get(:#{ name })
|
255
|
-
end
|
256
|
-
}
|
123
|
+
# @since 0.2.2
|
124
|
+
# @api private
|
125
|
+
def validations
|
126
|
+
@validations ||= ValidationSet.new
|
257
127
|
end
|
258
128
|
|
259
129
|
private
|
260
|
-
|
130
|
+
|
131
|
+
# Transfers attributes to a base class
|
261
132
|
#
|
262
|
-
# @
|
133
|
+
# @param base [Module] the base class to transfer attributes to
|
263
134
|
#
|
264
|
-
# @since 0.
|
135
|
+
# @since 0.2.2
|
265
136
|
# @api private
|
266
|
-
def
|
267
|
-
|
137
|
+
def transfer_validations_to_base(base)
|
138
|
+
validations.each do |attribute, options|
|
139
|
+
base.validates attribute, options
|
140
|
+
end
|
268
141
|
end
|
269
142
|
end
|
270
143
|
|
@@ -315,52 +188,8 @@ module Lotus
|
|
315
188
|
# # #<Lotus::Validations::Error:0x007fe00cee30d8 @attribute=:age, @validation=:size, @expected=18..99, @actual=17>
|
316
189
|
# # ]
|
317
190
|
# # }>
|
318
|
-
|
319
|
-
|
320
|
-
# Create a new instance with the given attributes
|
321
|
-
#
|
322
|
-
# @param attributes [#to_h] an Hash like object which contains the
|
323
|
-
# attributes
|
324
|
-
#
|
325
|
-
# @since 0.1.0
|
326
|
-
#
|
327
|
-
# @example Initialize with Hash
|
328
|
-
# require 'lotus/validations'
|
329
|
-
#
|
330
|
-
# class Signup
|
331
|
-
# include Lotus::Validations
|
332
|
-
#
|
333
|
-
# attribute :name
|
334
|
-
# end
|
335
|
-
#
|
336
|
-
# signup = Signup.new(name: 'Luca')
|
337
|
-
#
|
338
|
-
# @example Initialize with Hash like
|
339
|
-
# require 'lotus/validations'
|
340
|
-
#
|
341
|
-
# class Params
|
342
|
-
# def initialize(attributes)
|
343
|
-
# @attributes = Hash[*attributes]
|
344
|
-
# end
|
345
|
-
#
|
346
|
-
# def to_h
|
347
|
-
# @attributes.to_h
|
348
|
-
# end
|
349
|
-
# end
|
350
|
-
#
|
351
|
-
# class Signup
|
352
|
-
# include Lotus::Validations
|
353
|
-
#
|
354
|
-
# attribute :name
|
355
|
-
# end
|
356
|
-
#
|
357
|
-
# params = Params.new([:name, 'Luca'])
|
358
|
-
# signup = Signup.new(params)
|
359
|
-
#
|
360
|
-
# signup.name # => "Luca"
|
361
|
-
def initialize(attributes)
|
362
|
-
@attributes = Attributes.new(defined_attributes, attributes)
|
363
|
-
@errors = Errors.new
|
191
|
+
def errors
|
192
|
+
@errors ||= Errors.new
|
364
193
|
end
|
365
194
|
|
366
195
|
# Checks if the current data satisfies the defined validations
|
@@ -369,13 +198,10 @@ module Lotus
|
|
369
198
|
#
|
370
199
|
# @since 0.1.0
|
371
200
|
def valid?
|
372
|
-
|
201
|
+
validator = Validator.new(defined_validations, read_attributes)
|
202
|
+
@errors = validator.validate
|
373
203
|
|
374
|
-
|
375
|
-
@errors.add(name, *attribute.validate)
|
376
|
-
end
|
377
|
-
|
378
|
-
@errors.empty?
|
204
|
+
errors.empty?
|
379
205
|
end
|
380
206
|
|
381
207
|
# Iterates thru the defined attributes and their values
|
@@ -396,18 +222,30 @@ module Lotus
|
|
396
222
|
#
|
397
223
|
# @since 0.1.0
|
398
224
|
def to_h
|
399
|
-
|
225
|
+
Utils::Hash.new(read_attributes).deep_dup
|
400
226
|
end
|
401
227
|
|
402
228
|
private
|
403
|
-
# The set of user defined
|
229
|
+
# The set of user defined validations.
|
404
230
|
#
|
405
|
-
# @since 0.
|
231
|
+
# @since 0.2.2
|
406
232
|
# @api private
|
407
233
|
#
|
408
|
-
# @see Lotus::Validations::ClassMethods#
|
409
|
-
def
|
410
|
-
self.class.__send__(:
|
234
|
+
# @see Lotus::Validations::ClassMethods#validations
|
235
|
+
def defined_validations
|
236
|
+
self.class.__send__(:validations)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Builds a Hash of current attribute values.
|
240
|
+
#
|
241
|
+
# @since 0.2.2
|
242
|
+
# @api private
|
243
|
+
def read_attributes
|
244
|
+
{}.tap do |attributes|
|
245
|
+
defined_validations.each_key do |attribute|
|
246
|
+
attributes[attribute] = public_send(attribute)
|
247
|
+
end
|
248
|
+
end
|
411
249
|
end
|
412
250
|
end
|
413
251
|
end
|
data/lotus-validations.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'lotus/validations/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'lotus-validations'
|
8
8
|
spec.version = Lotus::Validations::VERSION
|
9
|
-
spec.authors = ['Luca Guidi']
|
10
|
-
spec.email = ['me@lucaguidi.com']
|
9
|
+
spec.authors = ['Luca Guidi', 'Trung Lê']
|
10
|
+
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com']
|
11
11
|
spec.summary = %q{Validations mixin for Ruby objects}
|
12
12
|
spec.description = %q{Validations mixin for Ruby objects and support for Lotus}
|
13
13
|
spec.homepage = 'http://lotusrb.org'
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
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', '>= 0.3.
|
22
|
+
spec.add_dependency 'lotus-utils', '~> 0.3', '>= 0.3.3'
|
23
23
|
|
24
24
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
25
25
|
spec.add_development_dependency 'minitest', '~> 5'
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lotus-validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
|
+
- Trung Lê
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2015-01-08 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: lotus-utils
|
@@ -19,7 +20,7 @@ dependencies:
|
|
19
20
|
version: '0.3'
|
20
21
|
- - ">="
|
21
22
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.3.
|
23
|
+
version: 0.3.3
|
23
24
|
type: :runtime
|
24
25
|
prerelease: false
|
25
26
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +30,7 @@ dependencies:
|
|
29
30
|
version: '0.3'
|
30
31
|
- - ">="
|
31
32
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.3.
|
33
|
+
version: 0.3.3
|
33
34
|
- !ruby/object:Gem::Dependency
|
34
35
|
name: bundler
|
35
36
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,6 +76,7 @@ dependencies:
|
|
75
76
|
description: Validations mixin for Ruby objects and support for Lotus
|
76
77
|
email:
|
77
78
|
- me@lucaguidi.com
|
79
|
+
- trung.le@ruby-journal.com
|
78
80
|
executables: []
|
79
81
|
extensions: []
|
80
82
|
extra_rdoc_files: []
|
@@ -85,11 +87,13 @@ files:
|
|
85
87
|
- lib/lotus-validations.rb
|
86
88
|
- lib/lotus/validations.rb
|
87
89
|
- lib/lotus/validations/attribute.rb
|
88
|
-
- lib/lotus/validations/
|
89
|
-
- lib/lotus/validations/
|
90
|
+
- lib/lotus/validations/attribute_definer.rb
|
91
|
+
- lib/lotus/validations/blank_value_checker.rb
|
90
92
|
- lib/lotus/validations/coercions.rb
|
91
93
|
- lib/lotus/validations/error.rb
|
92
94
|
- lib/lotus/validations/errors.rb
|
95
|
+
- lib/lotus/validations/validation_set.rb
|
96
|
+
- lib/lotus/validations/validator.rb
|
93
97
|
- lib/lotus/validations/version.rb
|
94
98
|
- lotus-validations.gemspec
|
95
99
|
homepage: http://lotusrb.org
|
@@ -112,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
116
|
version: '0'
|
113
117
|
requirements: []
|
114
118
|
rubyforge_project:
|
115
|
-
rubygems_version: 2.
|
119
|
+
rubygems_version: 2.4.5
|
116
120
|
signing_key:
|
117
121
|
specification_version: 4
|
118
122
|
summary: Validations mixin for Ruby objects
|
@@ -1,51 +0,0 @@
|
|
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 0.2.0
|
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
|
@@ -1,38 +0,0 @@
|
|
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
|