lotus-validations 0.0.0 → 0.1.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
  SHA1:
3
- metadata.gz: 20cf3a7591af700ba75a0ec7926f218e0ae37068
4
- data.tar.gz: 921f528200e6f2154174f74cbf6eac5db99c9070
3
+ metadata.gz: 88761697180386ed3a562170900b63ceb0618b03
4
+ data.tar.gz: e98d3b024612251600f74e104a3f6f43eb9bf33e
5
5
  SHA512:
6
- metadata.gz: 5fba96946b8509289218ecbd5b2007996173c37d08f119ebfb03ebdb0d1a51b1db049f7df4a8a0f461acda02ef8e1e2269975495e26ea6a20fc218af05c66e74
7
- data.tar.gz: 5263041936a6ca9decaca87cc81a373fa58e69b7c0bd3d3989171f2b40cfd0568e89fbe9c7587a338a3cc91edfa90e90e445e095be0c2a7ab2ecfa4f8ac1d922
6
+ metadata.gz: 76fac7ccbbafca4210be4ab570a3e5ae708378a08478aae7836a4dfd2e0ddf70c33a99bdaef93e544bbcd3d78917a65ce5f5868ea17e17788e75a1203471d7cb
7
+ data.tar.gz: 7185e7295684adaf616fa8abb450f11126adc2cc4ea8ed7d1769c27ebfad9a975b76e2727096832ff49e7cfa94a1d7c536293b612e823daaf90659e109502d46
File without changes
data/README.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # Lotus::Validations
2
2
 
3
- TODO: Write a gem description
3
+ Validations mixins for objects
4
+
5
+ ## Status
6
+
7
+ [![Gem Version](http://img.shields.io/gem/v/lotus-validations.svg)](https://badge.fury.io/rb/lotus-validations)
8
+ [![Build Status](http://img.shields.io/travis/lotus/validations/master.svg)](https://travis-ci.org/lotus/validations?branch=master)
9
+ [![Coverage](http://img.shields.io/coveralls/lotus/validations/master.svg)](https://coveralls.io/r/lotus/validations)
10
+ [![Code Climate](http://img.shields.io/codeclimate/github/lotus/validations.svg)](https://codeclimate.com/github/lotus/validations)
11
+ [![Dependencies](http://img.shields.io/gemnasium/lotus/validations.svg)](https://gemnasium.com/lotus/validations)
12
+ [![Inline Docs](http://inch-ci.org/github/lotus/validations.svg)](http://inch-ci.org/github/lotus/validations)
13
+
14
+ ## Contact
15
+
16
+ * Home page: http://lotusrb.org
17
+ * Mailing List: http://lotusrb.org/mailing-list
18
+ * API Doc: http://rdoc.info/gems/lotus-validations
19
+ * Bugs/Issues: https://github.com/lotus/validations/issues
20
+ * Support: http://stackoverflow.com/questions/tagged/lotus-ruby
21
+ * Chat: https://gitter.im/lotus/chat
22
+
23
+ ## Rubies
24
+
25
+ __Lotus::Validations__ supports Ruby (MRI) 2+ and JRuby 1.7 (with 2.0 mode).
4
26
 
5
27
  ## Installation
6
28
 
@@ -20,12 +42,353 @@ Or install it yourself as:
20
42
 
21
43
  ## Usage
22
44
 
23
- TODO: Write usage instructions here
45
+ `Lotus::Validations` is a set of lightweight validations for Ruby objects.
46
+
47
+ ### Attributes
48
+
49
+ The framework allows you to define attributes for each object.
50
+
51
+ It defines an initializer, whose attributes can be passed as a hash.
52
+ All unknown values are ignored, which is useful for whitelisting attributes.
53
+
54
+ ```ruby
55
+ require 'lotus/validations'
56
+
57
+ class Person
58
+ include Lotus::Validations
59
+
60
+ attribute :name
61
+ end
62
+
63
+ person = Person.new(name: 'Luca', age: 32)
64
+ person.name # => "Luca"
65
+ person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
66
+ ```
67
+
68
+ ### Coercions
69
+
70
+ If a Ruby class is passed to the `:type` option, the given value is coerced, accordingly.
71
+
72
+ #### Standard coercions
73
+
74
+ ```ruby
75
+ require 'lotus/validations'
76
+
77
+ class Person
78
+ include Lotus::Validations
79
+
80
+ attribute :fav_number, type: Integer
81
+ end
82
+
83
+ person = Person.new(fav_number: '23')
84
+ person.valid?
85
+
86
+ person.fav_number # => 23
87
+ ```
88
+
89
+ Allowed types are:
90
+
91
+ * `Array`
92
+ * `BigDecimal`
93
+ * `Boolean`
94
+ * `Date`
95
+ * `DateTime`
96
+ * `Float`
97
+ * `Hash`
98
+ * `Integer`
99
+ * `Pathname`
100
+ * `Set`
101
+ * `String`
102
+ * `Symbol`
103
+ * `Time`
104
+
105
+ #### Custom coercions
106
+
107
+ If a user defined class is specified, it can be freely used for coercion purposes.
108
+ The only limitation is that the constructor should have **arity of 1**.
109
+
110
+ ```ruby
111
+ require 'lotus/validations'
112
+
113
+ class FavNumber
114
+ def initialize(number)
115
+ @number = number
116
+ end
117
+ end
118
+
119
+ class BirthDate
120
+ end
121
+
122
+ class Person
123
+ include Lotus::Validations
124
+
125
+ attribute :fav_number, type: FavNumber
126
+ attribute :date, type: BirthDate
127
+ end
128
+
129
+ person = Person.new(fav_number: '23', date: 'Oct 23, 2014')
130
+ person.valid?
131
+
132
+ person.fav_number # => 23
133
+ person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
134
+ ```
135
+
136
+ ### Validations
137
+
138
+ Each attribute definition can receive a set of options to define one or more
139
+ validations.
140
+
141
+ **Validations are triggered when you invoke `#valid?`.**
142
+
143
+ #### Acceptance
144
+
145
+ An attribute is valid if it's value satisfies [Ruby's _truthiness_](http://ruby.about.com/od/control/a/Boolean-Expressions.htm).
146
+
147
+ ```ruby
148
+ require 'lotus/validations'
149
+
150
+ class Signup
151
+ include Lotus::Validations
152
+
153
+ attribute :terms_of_service, acceptance: true
154
+ end
155
+
156
+ signup = Signup.new(terms_of_service: '1')
157
+ signup.valid? # => true
158
+
159
+ signup = Signup.new(terms_of_service: '')
160
+ signup.valid? # => false
161
+ ```
162
+
163
+ #### Confirmation
164
+
165
+ An attribute is valid if it's value and the value of a corresponding attribute
166
+ is valid.
167
+
168
+ By convention, if you have a `password` attribute, the validation looks for `password_validation`.
169
+
170
+ ```ruby
171
+ require 'lotus/validations'
172
+
173
+ class Signup
174
+ include Lotus::Validations
175
+
176
+ attribute :password, confirmation: true
177
+ end
178
+
179
+ signup = Signup.new(password: 'secret', password_confirmation: 'secret')
180
+ signup.valid? # => true
181
+
182
+ signup = Signup.new(password: 'secret', password_confirmation: 'x')
183
+ signup.valid? # => false
184
+ ```
185
+
186
+ #### Exclusion
187
+
188
+ An attribute is valid, if the value isn't excluded from the value described by
189
+ the validator.
190
+
191
+ The validator value can be anything that responds to `#include?`.
192
+ In Ruby, this includes most of the core objects: `String`, `Enumerable` (`Array`, `Hash`,
193
+ `Range`, `Set`).
194
+
195
+ See also [Inclusion](#inclusion).
196
+
197
+ ```ruby
198
+ require 'lotus/validations'
199
+
200
+ class Signup
201
+ include Lotus::Validations
202
+
203
+ attribute :music, exclusion: ['pop']
204
+ end
205
+
206
+ signup = Signup.new(music: 'rock')
207
+ signup.valid? # => true
208
+
209
+ signup = Signup.new(music: 'pop')
210
+ signup.valid? # => false
211
+ ```
212
+
213
+ #### Format
214
+
215
+ An attribute is valid if it matches the given Regular Expression.
216
+
217
+ ```ruby
218
+ require 'lotus/validations'
219
+
220
+ class Signup
221
+ include Lotus::Validations
222
+
223
+ attribute :name, format: /\A[a-zA-Z]+\z/
224
+ end
225
+
226
+ signup = Signup.new(name: 'Luca')
227
+ signup.valid? # => true
228
+
229
+ signup = Signup.new(name: '23')
230
+ signup.valid? # => false
231
+ ```
232
+
233
+ #### Inclusion
234
+
235
+ An attribute is valid, if the value provided is included in the validator's
236
+ value.
237
+
238
+ The validator value can be anything that responds to `#include?`.
239
+ In Ruby, this includes most of the core objects: like `String`, `Enumerable` (`Array`, `Hash`,
240
+ `Range`, `Set`).
241
+
242
+ See also [Exclusion](#exclusion).
243
+
244
+ ```ruby
245
+ require 'prime'
246
+ require 'lotus/validations'
247
+
248
+ class PrimeNumbers
249
+ def initialize(limit)
250
+ @numbers = Prime.each(limit).to_a
251
+ end
252
+
253
+ def include?(number)
254
+ @numbers.include?(number)
255
+ end
256
+ end
257
+
258
+ class Signup
259
+ include Lotus::Validations
260
+
261
+ attribute :age, inclusion: 18..99
262
+ attribute :fav_number, inclusion: PrimeNumbers.new(100)
263
+ end
264
+
265
+ signup = Signup.new(age: 32)
266
+ signup.valid? # => true
267
+
268
+ signup = Signup.new(age: 17)
269
+ signup.valid? # => false
270
+
271
+ signup = Signup.new(fav_number: 23)
272
+ signup.valid? # => true
273
+
274
+ signup = Signup.new(fav_number: 8)
275
+ signup.valid? # => false
276
+ ```
277
+
278
+ #### Presence
279
+
280
+ An attribute is valid if present.
281
+
282
+ ```ruby
283
+ require 'lotus/validations'
284
+
285
+ class Signup
286
+ include Lotus::Validations
287
+
288
+ attribute :name, presence: true
289
+ end
290
+
291
+ signup = Signup.new(name: 'Luca')
292
+ signup.valid? # => true
293
+
294
+ signup = Signup.new(name: '')
295
+ signup.valid? # => false
296
+
297
+ signup = Signup.new(name: nil)
298
+ signup.valid? # => false
299
+ ```
300
+
301
+ #### Size
302
+
303
+ An attribute is valid if it's `#size` falls within the described value.
304
+
305
+ ```ruby
306
+ require 'lotus/validations'
307
+
308
+ class Signup
309
+ MEGABYTE = 1024 ** 2
310
+ include Lotus::Validations
311
+
312
+ attribute :ssn, size: 11 # exact match
313
+ attribute :password, size: 8..64 # range
314
+ attribute :avatar, size 1..(5 * MEGABYTE)
315
+ end
316
+
317
+ signup = Signup.new(password: 'a-very-long-password')
318
+ signup.valid? # => true
319
+
320
+ signup = Signup.new(password: 'short')
321
+ signup.valid? # => false
322
+ ```
323
+
324
+ **Note that in the example above you are able to validate the weight of the file,
325
+ because Ruby's `File` and `Tempfile` both respond to `#size`.**
326
+
327
+ #### Uniqueness
328
+
329
+ Uniqueness validations aren't implemented because this library doesn't deal with persistence.
330
+ The other reason is that this isn't an effective way to ensure uniqueness of a value in a database.
331
+
332
+ Please read more at: [The Perils of Uniqueness Validations](http://robots.thoughtbot.com/the-perils-of-uniqueness-validations).
333
+
334
+ ### Complete example
335
+
336
+ ```ruby
337
+ require 'lotus/validations'
338
+
339
+ class Signup
340
+ include Lotus::Validations
341
+
342
+ attribute :first_name, presence: true
343
+ attribute :last_name, presence: true
344
+ attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
345
+ attribute :password, presence: true, confirmation: true, size: 8..64
346
+ end
347
+ ```
348
+
349
+ ### Errors
350
+
351
+ When you invoke `#valid?`, validations errors are available at `#errors`.
352
+ It's a set of errors grouped by attribute. Each error contains the name of the
353
+ invalid attribute, the failed validation, the expected value and the current one.
354
+
355
+ ```ruby
356
+ require 'lotus/validations'
357
+
358
+ class Signup
359
+ include Lotus::Validations
360
+
361
+ attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
362
+ attribute :age, size: 18..99
363
+ end
364
+
365
+ signup = Signup.new(email: 'user@example.org')
366
+ signup.valid? # => true
367
+
368
+ signup = Signup.new(email: '', age: 17)
369
+ signup.valid? # => false
370
+
371
+ signup.errors
372
+ # => #<Lotus::Validations::Errors:0x007fe00ced9b78
373
+ # @errors={
374
+ # :email=>[
375
+ # #<Lotus::Validations::Error:0x007fe00cee3290 @attribute=:email, @validation=:presence, @expected=true, @actual="">,
376
+ # #<Lotus::Validations::Error:0x007fe00cee31f0 @attribute=:email, @validation=:format, @expected=/\A(.*)@(.*)\.(.*)\z/, @actual="">
377
+ # ],
378
+ # :age=>[
379
+ # #<Lotus::Validations::Error:0x007fe00cee30d8 @attribute=:age, @validation=:size, @expected=18..99, @actual=17>
380
+ # ]
381
+ # }>
382
+ ```
24
383
 
25
384
  ## Contributing
26
385
 
27
- 1. Fork it ( https://github.com/[my-github-username]/lotus-validations/fork )
386
+ 1. Fork it ( https://github.com/lotus/lotus-validations/fork )
28
387
  2. Create your feature branch (`git checkout -b my-new-feature`)
29
388
  3. Commit your changes (`git commit -am 'Add some feature'`)
30
389
  4. Push to the branch (`git push origin my-new-feature`)
31
390
  5. Create a new Pull Request
391
+
392
+ ## Copyright
393
+
394
+ Copyright 2014 Luca Guidi – Released under MIT License
@@ -0,0 +1 @@
1
+ require 'lotus/validations'
@@ -1,7 +1,398 @@
1
- require "lotus/validations/version"
1
+ require 'lotus/validations/version'
2
+ require 'lotus/validations/errors'
3
+ require 'lotus/validations/attribute_validator'
2
4
 
3
5
  module Lotus
6
+ # Lotus::Validations is a set of lightweight validations for Ruby objects.
7
+ #
8
+ # @since 0.1.0
4
9
  module Validations
5
- # Your code goes here...
10
+
11
+ # Override Ruby's hook for modules.
12
+ #
13
+ # @param base [Class] the target action
14
+ #
15
+ # @since 0.1.0
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
+ # Validations DSL
24
+ #
25
+ # @since 0.1.0
26
+ module ClassMethods
27
+ # Define an attribute
28
+ #
29
+ # @param name [#to_sym] the name of the attribute
30
+ # @param options [Hash] optional set of validations
31
+ # @option options [Class] :type the Ruby type used to coerce the value
32
+ # @option options [TrueClass,FalseClass] :acceptance requires Ruby
33
+ # thruthiness of the value
34
+ # @option options [TrueClass,FalseClass] :confirmation requires the value
35
+ # to be confirmed twice
36
+ # @option options [#include?] :exclusion requires the value NOT be
37
+ # included in the given collection
38
+ # @option options [Regexp] :format requires value to match the given
39
+ # Regexp
40
+ # @option options [#include?] :inclusion requires the value BE included in
41
+ # the given collection
42
+ # @option options [TrueClass,FalseClass] :presence requires the value be
43
+ # included in the given collection
44
+ # @option options [Numeric,Range] :size requires value's to be equal or
45
+ # included by the given validator
46
+ #
47
+ # @raise [ArgumentError] if an unknown or mispelled validation is given
48
+ #
49
+ # @example Attributes
50
+ # require 'lotus/validations'
51
+ #
52
+ # class Person
53
+ # include Lotus::Validations
54
+ #
55
+ # attribute :name
56
+ # end
57
+ #
58
+ # person = Person.new(name: 'Luca', age: 32)
59
+ # person.name # => "Luca"
60
+ # person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
61
+ #
62
+ # @example Standard coercions
63
+ # require 'lotus/validations'
64
+ #
65
+ # class Person
66
+ # include Lotus::Validations
67
+ #
68
+ # attribute :fav_number, type: Integer
69
+ # end
70
+ #
71
+ # person = Person.new(fav_number: '23')
72
+ # person.valid?
73
+ #
74
+ # person.fav_number # => 23
75
+ #
76
+ # @example Custom coercions
77
+ # require 'lotus/validations'
78
+ #
79
+ # class FavNumber
80
+ # def initialize(number)
81
+ # @number = number
82
+ # end
83
+ # end
84
+ #
85
+ # class BirthDate
86
+ # end
87
+ #
88
+ # class Person
89
+ # include Lotus::Validations
90
+ #
91
+ # attribute :fav_number, type: FavNumber
92
+ # attribute :date, type: BirthDate
93
+ # end
94
+ #
95
+ # person = Person.new(fav_number: '23', date: 'Oct 23, 2014')
96
+ # person.valid?
97
+ #
98
+ # person.fav_number # => 23
99
+ # person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
100
+ #
101
+ # @example Acceptance
102
+ # require 'lotus/validations'
103
+ #
104
+ # class Signup
105
+ # include Lotus::Validations
106
+ #
107
+ # attribute :terms_of_service, acceptance: true
108
+ # end
109
+ #
110
+ # signup = Signup.new(terms_of_service: '1')
111
+ # signup.valid? # => true
112
+ #
113
+ # signup = Signup.new(terms_of_service: '')
114
+ # signup.valid? # => false
115
+ #
116
+ # @example Confirmation
117
+ # require 'lotus/validations'
118
+ #
119
+ # class Signup
120
+ # include Lotus::Validations
121
+ #
122
+ # attribute :password, confirmation: true
123
+ # end
124
+ #
125
+ # signup = Signup.new(password: 'secret', password_confirmation: 'secret')
126
+ # signup.valid? # => true
127
+ #
128
+ # signup = Signup.new(password: 'secret', password_confirmation: 'x')
129
+ # signup.valid? # => false
130
+ #
131
+ # @example Exclusion
132
+ # require 'lotus/validations'
133
+ #
134
+ # class Signup
135
+ # include Lotus::Validations
136
+ #
137
+ # attribute :music, exclusion: ['pop']
138
+ # end
139
+ #
140
+ # signup = Signup.new(music: 'rock')
141
+ # signup.valid? # => true
142
+ #
143
+ # signup = Signup.new(music: 'pop')
144
+ # signup.valid? # => false
145
+ #
146
+ # @example Format
147
+ # require 'lotus/validations'
148
+ #
149
+ # class Signup
150
+ # include Lotus::Validations
151
+ #
152
+ # attribute :name, format: /\A[a-zA-Z]+\z/
153
+ # end
154
+ #
155
+ # signup = Signup.new(name: 'Luca')
156
+ # signup.valid? # => true
157
+ #
158
+ # signup = Signup.new(name: '23')
159
+ # signup.valid? # => false
160
+ #
161
+ # @example Inclusion
162
+ # require 'lotus/validations'
163
+ #
164
+ # class Signup
165
+ # include Lotus::Validations
166
+ #
167
+ # attribute :age, inclusion: 18..99
168
+ # end
169
+ #
170
+ # signup = Signup.new(age: 32)
171
+ # signup.valid? # => true
172
+ #
173
+ # signup = Signup.new(age: 17)
174
+ # signup.valid? # => false
175
+ #
176
+ # @example Presence
177
+ # require 'lotus/validations'
178
+ #
179
+ # class Signup
180
+ # include Lotus::Validations
181
+ #
182
+ # attribute :name, presence: true
183
+ # end
184
+ #
185
+ # signup = Signup.new(name: 'Luca')
186
+ # signup.valid? # => true
187
+ #
188
+ # signup = Signup.new(name: nil)
189
+ # signup.valid? # => false
190
+ #
191
+ # @example Size
192
+ # require 'lotus/validations'
193
+ #
194
+ # class Signup
195
+ # MEGABYTE = 1024 ** 2
196
+ # include Lotus::Validations
197
+ #
198
+ # attribute :ssn, size: 11 # exact match
199
+ # attribute :password, size: 8..64 # range
200
+ # attribute :avatar, size 1..(5 * MEGABYTE)
201
+ # end
202
+ #
203
+ # signup = Signup.new(password: 'a-very-long-password')
204
+ # signup.valid? # => true
205
+ #
206
+ # signup = Signup.new(password: 'short')
207
+ # signup.valid? # => false
208
+ def attribute(name, options = {})
209
+ attributes[name.to_sym] = validate_options!(name, options)
210
+
211
+ class_eval %{
212
+ def #{ name }
213
+ @attributes[:#{ name }]
214
+ end
215
+ }
216
+ end
217
+
218
+ private
219
+ # Set of user defined attributes
220
+ #
221
+ # @return [Hash]
222
+ #
223
+ # @since 0.1.0
224
+ # @api private
225
+ def attributes
226
+ @attributes ||= Hash.new
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]
255
+ end
256
+ end
257
+
258
+ # Validation errors
259
+ #
260
+ # @return [Lotus::Validations::Errors] the set of validation errors
261
+ #
262
+ # @since 0.1.0
263
+ #
264
+ # @see Lotus::Validations::Errors
265
+ #
266
+ # @example Valid attributes
267
+ # require 'lotus/validations'
268
+ #
269
+ # class Signup
270
+ # include Lotus::Validations
271
+ #
272
+ # attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
273
+ # end
274
+ #
275
+ # signup = Signup.new(email: 'user@example.org')
276
+ # signup.valid? # => true
277
+ #
278
+ # signup.errors
279
+ # # => #<Lotus::Validations::Errors:0x007fd594ba9228 @errors={}>
280
+ #
281
+ # @example Invalid attributes
282
+ # require 'lotus/validations'
283
+ #
284
+ # class Signup
285
+ # include Lotus::Validations
286
+ #
287
+ # attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
288
+ # attribute :age, size: 18..99
289
+ # end
290
+ #
291
+ # signup = Signup.new(email: '', age: 17)
292
+ # signup.valid? # => false
293
+ #
294
+ # signup.errors
295
+ # # => #<Lotus::Validations::Errors:0x007fe00ced9b78
296
+ # # @errors={
297
+ # # :email=>[
298
+ # # #<Lotus::Validations::Error:0x007fe00cee3290 @attribute=:email, @validation=:presence, @expected=true, @actual="">,
299
+ # # #<Lotus::Validations::Error:0x007fe00cee31f0 @attribute=:email, @validation=:format, @expected=/\A(.*)@(.*)\.(.*)\z/, @actual="">
300
+ # # ],
301
+ # # :age=>[
302
+ # # #<Lotus::Validations::Error:0x007fe00cee30d8 @attribute=:age, @validation=:size, @expected=18..99, @actual=17>
303
+ # # ]
304
+ # # }>
305
+ attr_reader :errors
306
+
307
+ # Create a new instance with the given attributes
308
+ #
309
+ # @param attributes [#to_h] an Hash like object which contains the
310
+ # attributes
311
+ #
312
+ # @since 0.1.0
313
+ #
314
+ # @example Initialize with Hash
315
+ # require 'lotus/validations'
316
+ #
317
+ # class Signup
318
+ # include Lotus::Validations
319
+ #
320
+ # attribute :name
321
+ # end
322
+ #
323
+ # signup = Signup.new(name: 'Luca')
324
+ #
325
+ # @example Initialize with Hash like
326
+ # require 'lotus/validations'
327
+ #
328
+ # class Params
329
+ # def initialize(attributes)
330
+ # @attributes = Hash[*attributes]
331
+ # end
332
+ #
333
+ # def to_h
334
+ # @attributes.to_h
335
+ # end
336
+ # end
337
+ #
338
+ # class Signup
339
+ # include Lotus::Validations
340
+ #
341
+ # attribute :name
342
+ # end
343
+ #
344
+ # params = Params.new([:name, 'Luca'])
345
+ # signup = Signup.new(params)
346
+ #
347
+ # signup.name # => "Luca"
348
+ def initialize(attributes)
349
+ @attributes = attributes.to_h
350
+ @errors = Errors.new
351
+ end
352
+
353
+ # Checks if the current data satisfies the defined validations
354
+ #
355
+ # @return [TrueClass,FalseClass] the result of the validations
356
+ #
357
+ # @since 0.1.0
358
+ def valid?
359
+ @errors.clear
360
+
361
+ _attributes.each do |name, options|
362
+ AttributeValidator.new(self, name, options).validate!
363
+ end
364
+
365
+ @errors.empty?
366
+ end
367
+
368
+ protected
369
+ # Returns the attributes passed at the initialize time
370
+ #
371
+ # @return [Hash] attributes
372
+ #
373
+ # @since 0.1.0
374
+ # @api private
375
+ #
376
+ # @example
377
+ # require 'lotus/validations'
378
+ #
379
+ # class Signup
380
+ # include Lotus::Validations
381
+ #
382
+ # attribute :email
383
+ # end
384
+ #
385
+ # signup = Signup.new(email: 'user@example.org')
386
+ # signup.attributes # => {:email=>"user@example.org"}
387
+ attr_reader :attributes
388
+
389
+ private
390
+ # @since 0.1.0
391
+ # @api private
392
+ #
393
+ # @see Lotus::Validations::ClassMethods#attributes
394
+ def _attributes
395
+ self.class.__send__(:attributes)
396
+ end
6
397
  end
7
398
  end