lotus-validations 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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