hanami-validations 0.0.0 → 0.5.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: cf76bc3940612ffdc8aa64e07941219547ca0c32
4
- data.tar.gz: 04ad62428f8e83fa41ec449f84bd38ade15d0345
3
+ metadata.gz: adeb97811a77f27c28ac940395e0fab28c0670c0
4
+ data.tar.gz: d6bc2be331bde334ff930692e1b66458b08f04c5
5
5
  SHA512:
6
- metadata.gz: 17a5e5c9f565fd7101ed62a12883d2ecb8c8467d5a0c2da0f081030ea3b0066a1f6119d38b17b97fb24b944058264ae1ee06c4e23ae48cf33305fb51403146e6
7
- data.tar.gz: 4863bd75a0ce12a0e4ef59ede8d24959917b6d20b469d29cf6ac5ebdcadccd4c4c1e2dee68dd59d0418c398509d9d9711493848dd73f19b2dc06d3937702f5da
6
+ metadata.gz: 5fb1f27b1db7511d4b2cbb926acba8650596615c171901d27c2dcc5c5c5d6ed55ff0edb41c47d267441b98c07780ec90eb900ebc3d4240c78e55f05f07762eeb
7
+ data.tar.gz: 517a5991fae90f9c8b83fe0dbf96ad9e86ff93ac0898c9b8fc296da16547a78d9fbb7d8341772fc9e32bdc4454f507cf59a382e9c386202b0c5485fa4c15468e
data/CHANGELOG.md ADDED
@@ -0,0 +1,89 @@
1
+ # Hanami::Validations
2
+ Validations mixin for Ruby objects
3
+
4
+ ## v0.5.0 - 2016-01-22
5
+ ### Changed
6
+ - [Luca Guidi] Renamed the project
7
+
8
+ ## v0.4.0 - 2016-01-12
9
+ ## Changed
10
+ - [Hélio Costa e Silva & Luca Guidi] Ignore blank values for format and size validation
11
+
12
+ ### Fixed
13
+ - [Pascal Betz] Ensure acceptance validation to reject blank strings
14
+
15
+ ## v0.3.3 - 2015-09-30
16
+ ### Added
17
+ - [Luca Guidi] Official support for JRuby 9k+
18
+
19
+ ## v0.3.2 - 2015-05-22
20
+ ### Added
21
+ - [deepj] Introduced `Lotus::Validations#invalid?`
22
+
23
+ ## v0.3.1 - 2015-05-15
24
+ ### Fixed
25
+ - [Luca Guidi] Fixed Hash serialization for nested validations. It always return nested `::Hash` structure.
26
+ - [Alfonso Uceda Pompa & Dmitry Tymchuk] Fixed Hash serialization when `Lotus::Entity` is included in the same class.
27
+
28
+ ## v0.3.0 - 2015-03-23
29
+
30
+ ## v0.2.4 - 2015-01-30
31
+ ### Added
32
+ - [Steve Hodgkiss] Introduced `Lotus::Validations::Error#attribute_name`
33
+ - [Steve Hodgkiss] Nested validations
34
+
35
+ ### Changed
36
+ - [Steve Hodgkiss] `Lotus::Validations::Error#name` returns the complete attribute name (Eg. `first_name` or `address.street`)
37
+
38
+ ## v0.2.3 - 2015-01-12
39
+ ### Added
40
+ - [Luca Guidi] Compatibility with Lotus::Entity
41
+
42
+ ### Fixed
43
+ - [Luca Guidi] Ensure `.validates` usage to not raise `ArgumentError` when `:type` option is passed
44
+ - [Luca Guidi] Ensure to assign attributes when only `.validates` is used
45
+
46
+ ## v0.2.2 - 2015-01-08
47
+ ### Added
48
+ - [Steve Hodgkiss] Introduced `Validations.validates`. It defines validations, for already existing attributes.
49
+
50
+ ## v0.2.1 - 2014-12-23
51
+ ### Added
52
+ - [Luca Guidi] Introduced `Validations::Errors#to_h` and `to_a`
53
+ - [Luca Guidi] Introduced `Validations::Errors#any?`
54
+ - [Luca Guidi] Official support for Ruby 2.2
55
+
56
+ ### Fixed
57
+ - [Satoshi Amemiya] Made `Validations#valid?` idempotent
58
+
59
+ ## v0.2.0 - 2014-11-23
60
+ ### Added
61
+ - [Luca Guidi] Skip attribute whitelisting when a validator does not define any attribute
62
+ - [Luca Guidi] Official support for Rubinius 2.3+
63
+ - [Luca Guidi] Implemented `#each` in order to allow bulk operations on attributes
64
+ - [Luca Guidi] Implemented `#to_h` to make validations usable by other libraries
65
+ - [Luca Guidi] Made `#initialize` to accept Hashes with strings as keys, but only for declared attributes
66
+ - [Luca Guidi] Lazy coercions, from now on `valid?` is not required to obtain a coerced value from a single attribute
67
+ - [Rik Tonnard] Made validators reusable by allowing infinite inclusion
68
+
69
+ ## v0.1.0 - 2014-10-23
70
+ ### Added
71
+ - [Luca Guidi] Made `#initialize` to accept any object that implements `#to_h`
72
+ - [Luca Guidi] Custom coercions for user defined classes
73
+ - [Luca Guidi] Raise an exception at the load time when a validation is not recognized
74
+ - [Luca Guidi] Allow validators inheritance
75
+ - [Luca Guidi] Confirmation validation
76
+ - [Luca Guidi] Exclusion validation
77
+ - [Luca Guidi] Size validation
78
+ - [Luca Guidi] Acceptance validation
79
+ - [Jeremy Stephens] Inclusion validation
80
+ - [Luca Guidi] Format validation
81
+ - [Luca Guidi] Presence validation
82
+ - [Luca Guidi] Coercions
83
+ - [Luca Guidi] Basic module inclusion
84
+ - [Luca Guidi] Official support for JRuby 1.7+ (with 2.0 mode)
85
+ - [Luca Guidi] Official support for MRI 2.0+
86
+
87
+ ### Fixed
88
+ - [Jeremy Stephens] Ensure to not fail validations when coerce falsey values
89
+ - [Luca Guidi] Ensure `Lotus::Validations#valid?` to be idempotent
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2014-2016 Luca Guidi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,8 +1,28 @@
1
1
  # Hanami::Validations
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/hanami/validations`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Validations mixins for objects
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Status
6
+
7
+ [![Gem Version](http://img.shields.io/gem/v/hanami-validations.svg)](https://badge.fury.io/rb/hanami-validations)
8
+ [![Build Status](http://img.shields.io/travis/hanami/validations/master.svg)](https://travis-ci.org/hanami/validations?branch=master)
9
+ [![Coverage](http://img.shields.io/coveralls/hanami/validations/master.svg)](https://coveralls.io/r/hanami/validations)
10
+ [![Code Climate](http://img.shields.io/codeclimate/github/hanami/validations.svg)](https://codeclimate.com/github/hanami/validations)
11
+ [![Dependencies](http://img.shields.io/gemnasium/hanami/validations.svg)](https://gemnasium.com/hanami/validations)
12
+ [![Inline Docs](http://inch-ci.org/github/hanami/validations.svg)](http://inch-ci.org/github/hanami/validations)
13
+
14
+ ## Contact
15
+
16
+ * Home page: http://hanamirb.org
17
+ * Mailing List: http://hanamirb.org/mailing-list
18
+ * API Doc: http://rdoc.info/gems/hanami-validations
19
+ * Bugs/Issues: https://github.com/hanami/validations/issues
20
+ * Support: http://stackoverflow.com/questions/tagged/hanami
21
+ * Chat: http://chat.hanamirb.org
22
+
23
+ ## Rubies
24
+
25
+ __Hanami::Validations__ supports Ruby (MRI) 2+, JRuby 9k+
6
26
 
7
27
  ## Installation
8
28
 
@@ -22,15 +42,547 @@ Or install it yourself as:
22
42
 
23
43
  ## Usage
24
44
 
25
- TODO: Write usage instructions here
45
+ `Hanami::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 'hanami/validations'
56
+
57
+ class Person
58
+ include Hanami::Validations
59
+
60
+ attribute :name, presence: true
61
+ attribute :email, presence: true
62
+ end
63
+
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.
68
+ ```
69
+
70
+ #### Blank Values
71
+
72
+ The framework will treat as valid any blank attributes, __without__ `presence`, for both `format` and `size` predicates.
73
+
74
+ ```ruby
75
+ require 'hanami/validations'
76
+
77
+ class Person
78
+ include Hanami::Validations
79
+
80
+ attribute :name, type: String, size: 5..45
81
+ attribute :email, type: String, size: 20..80, format: /@/
82
+ attribute :skills, type: Array, size: 1..3
83
+ attribute :keys, type: Hash, size: 1..3
84
+ end
85
+
86
+ Person.new.valid? # < true
87
+ Person.new(name: '').valid? # < true
88
+ Person.new(skills: '').valid? # < true
89
+ Person.new(skills: ['ruby', 'hanami']).valid? # < true
90
+
91
+ Person.new(skills: []).valid? # < false
92
+ Person.new(keys: {}).valid? # < false
93
+ Person.new(keys: {a: :b}, skills: []).valid? # < false
94
+ ```
95
+
96
+ If you want to _disable_ this behaviour, please, refer to [presence](https://github.com/hanami/validations#presence).
97
+
98
+ ### Validations
99
+
100
+ If you prefer Hanami::Validations to **only define validations**, but **not attributes**,
101
+ you can use the following alternative syntax.
102
+
103
+ ```ruby
104
+ require 'hanami/validations'
105
+
106
+ class Person
107
+ include Hanami::Validations
108
+ attr_accessor :name, :email
109
+
110
+ # Custom initializer
111
+ def initialize(attributes = {})
112
+ @name, @email = attributes.values_at(:name, :email)
113
+ end
114
+
115
+ validates :name, presence: true
116
+ validates :email, presence: true
117
+ end
118
+
119
+ person = Person.new(name: 'Luca', email: 'me@example.org')
120
+ person.name # => "Luca"
121
+ person.email # => "me@example.org"
122
+ ```
123
+
124
+ This is a bit more verbose, but offers a great level of flexibility for your
125
+ Ruby objects. It also allows to use Hanami::Validations in combination with
126
+ **other frameworks**.
127
+
128
+ ### Coercions
129
+
130
+ If a Ruby class is passed to the `:type` option, the given value is coerced, accordingly.
131
+
132
+ #### Standard coercions
133
+
134
+ ```ruby
135
+ require 'hanami/validations'
136
+
137
+ class Person
138
+ include Hanami::Validations
139
+
140
+ attribute :fav_number, type: Integer
141
+ end
142
+
143
+ person = Person.new(fav_number: '23')
144
+ person.valid?
145
+
146
+ person.fav_number # => 23
147
+ ```
148
+
149
+ Allowed types are:
150
+
151
+ * `Array`
152
+ * `BigDecimal`
153
+ * `Boolean`
154
+ * `Date`
155
+ * `DateTime`
156
+ * `Float`
157
+ * `Hash`
158
+ * `Integer`
159
+ * `Pathname`
160
+ * `Set`
161
+ * `String`
162
+ * `Symbol`
163
+ * `Time`
164
+
165
+ #### Custom coercions
166
+
167
+ If a user defined class is specified, it can be freely used for coercion purposes.
168
+ The only limitation is that the constructor should have **arity of 1**.
169
+
170
+ ```ruby
171
+ require 'hanami/validations'
172
+
173
+ class FavNumber
174
+ def initialize(number)
175
+ @number = number
176
+ end
177
+ end
178
+
179
+ class BirthDate
180
+ end
181
+
182
+ class Person
183
+ include Hanami::Validations
184
+
185
+ attribute :fav_number, type: FavNumber
186
+ attribute :date, type: BirthDate
187
+ end
188
+
189
+ person = Person.new(fav_number: '23', date: 'Oct 23, 2014')
190
+ person.valid?
191
+
192
+ person.fav_number # => #<FavNumber:0x007ffc644bba00 @number="23">
193
+ person.date # => this raises an error, because BirthDate#initialize doesn't accept any arg
194
+ ```
195
+
196
+ ### Validations
197
+
198
+ Each attribute definition can receive a set of options to define one or more
199
+ validations.
200
+
201
+ **Validations are triggered when you invoke `#valid?`.**
202
+
203
+ #### Acceptance
204
+
205
+ An attribute is valid if its value is _truthy_.
206
+
207
+ ```ruby
208
+ require 'hanami/validations'
209
+
210
+ class Signup
211
+ include Hanami::Validations
212
+
213
+ attribute :terms_of_service, acceptance: true
214
+ end
215
+
216
+ signup = Signup.new(terms_of_service: '1')
217
+ signup.valid? # => true
218
+
219
+ signup = Signup.new(terms_of_service: 'true')
220
+ signup.valid? # => true
221
+
222
+ signup = Signup.new(terms_of_service: '')
223
+ signup.valid? # => false
224
+
225
+ signup = Signup.new(terms_of_service: '0')
226
+ signup.valid? # => false
227
+ ```
228
+
229
+ #### Confirmation
230
+
231
+ An attribute is valid if its value and the value of a corresponding attribute
232
+ is valid.
233
+
234
+ By convention, if you have a `password` attribute, the validation looks for `password_confirmation`.
235
+
236
+ ```ruby
237
+ require 'hanami/validations'
238
+
239
+ class Signup
240
+ include Hanami::Validations
241
+
242
+ attribute :password, confirmation: true
243
+ end
244
+
245
+ signup = Signup.new(password: 'secret', password_confirmation: 'secret')
246
+ signup.valid? # => true
247
+
248
+ signup = Signup.new(password: 'secret', password_confirmation: 'x')
249
+ signup.valid? # => false
250
+ ```
251
+
252
+ #### Exclusion
253
+
254
+ An attribute is valid, if the value isn't excluded from the value described by
255
+ the validator.
256
+
257
+ The validator value can be anything that responds to `#include?`.
258
+ In Ruby, this includes most of the core objects: `String`, `Enumerable` (`Array`, `Hash`,
259
+ `Range`, `Set`).
260
+
261
+ See also [Inclusion](#inclusion).
262
+
263
+ ```ruby
264
+ require 'hanami/validations'
265
+
266
+ class Signup
267
+ include Hanami::Validations
268
+
269
+ attribute :music, exclusion: ['pop']
270
+ end
271
+
272
+ signup = Signup.new(music: 'rock')
273
+ signup.valid? # => true
274
+
275
+ signup = Signup.new(music: 'pop')
276
+ signup.valid? # => false
277
+ ```
278
+
279
+ #### Format
280
+
281
+ An attribute is valid if it matches the given Regular Expression.
282
+
283
+ ```ruby
284
+ require 'hanami/validations'
285
+
286
+ class Signup
287
+ include Hanami::Validations
288
+
289
+ attribute :name, format: /\A[a-zA-Z]+\z/
290
+ end
26
291
 
27
- ## Development
292
+ signup = Signup.new(name: 'Luca')
293
+ signup.valid? # => true
28
294
 
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
295
+ signup = Signup.new(name: '23')
296
+ signup.valid? # => false
297
+ ```
298
+
299
+ #### Inclusion
300
+
301
+ An attribute is valid, if the value provided is included in the validator's
302
+ value.
303
+
304
+ The validator value can be anything that responds to `#include?`.
305
+ In Ruby, this includes most of the core objects: like `String`, `Enumerable` (`Array`, `Hash`,
306
+ `Range`, `Set`).
307
+
308
+ See also [Exclusion](#exclusion).
309
+
310
+ ```ruby
311
+ require 'prime'
312
+ require 'hanami/validations'
313
+
314
+ class PrimeNumbers
315
+ def initialize(limit)
316
+ @numbers = Prime.each(limit).to_a
317
+ end
318
+
319
+ def include?(number)
320
+ @numbers.include?(number)
321
+ end
322
+ end
323
+
324
+ class Signup
325
+ include Hanami::Validations
326
+
327
+ attribute :age, inclusion: 18..99
328
+ attribute :fav_number, inclusion: PrimeNumbers.new(100)
329
+ end
330
+
331
+ signup = Signup.new(age: 32)
332
+ signup.valid? # => true
333
+
334
+ signup = Signup.new(age: 17)
335
+ signup.valid? # => false
336
+
337
+ signup = Signup.new(fav_number: 23)
338
+ signup.valid? # => true
339
+
340
+ signup = Signup.new(fav_number: 8)
341
+ signup.valid? # => false
342
+ ```
343
+
344
+ #### Presence
345
+
346
+ An attribute is valid if present.
347
+
348
+ ```ruby
349
+ require 'hanami/validations'
350
+
351
+ class Signup
352
+ include Hanami::Validations
353
+
354
+ attribute :name, presence: true
355
+ end
356
+
357
+ signup = Signup.new(name: 'Luca')
358
+ signup.valid? # => true
359
+
360
+ signup = Signup.new(name: '')
361
+ signup.valid? # => false
362
+
363
+ signup = Signup.new(name: nil)
364
+ signup.valid? # => false
365
+ ```
366
+
367
+ #### Size
368
+
369
+ An attribute is valid if its `#size` falls within the described value.
370
+
371
+ ```ruby
372
+ require 'hanami/validations'
373
+
374
+ class Signup
375
+ MEGABYTE = 1024 ** 2
376
+ include Hanami::Validations
377
+
378
+ attribute :ssn, size: 11 # exact match
379
+ attribute :password, size: 8..64 # range
380
+ attribute :avatar, size: 1..(5 * MEGABYTE)
381
+ end
382
+
383
+ signup = Signup.new(password: 'a-very-long-password')
384
+ signup.valid? # => true
385
+
386
+ signup = Signup.new(password: 'short')
387
+ signup.valid? # => false
388
+ ```
389
+
390
+ **Note that in the example above you are able to validate the weight of the file,
391
+ because Ruby's `File` and `Tempfile` both respond to `#size`.**
392
+
393
+ #### Uniqueness
394
+
395
+ Uniqueness validations aren't implemented because this library doesn't deal with persistence.
396
+ The other reason is that this isn't an effective way to ensure uniqueness of a value in a database.
397
+
398
+ Please read more at: [The Perils of Uniqueness Validations](http://robots.thoughtbot.com/the-perils-of-uniqueness-validations).
399
+
400
+ ### Nested validations
401
+
402
+ Nested validations are handled with a nested block syntax.
403
+
404
+ ```ruby
405
+ class ShippingDetails
406
+ include Hanami::Validations
407
+
408
+ attribute :full_name, presence: true
409
+
410
+ attribute :address do
411
+ attribute :street, presence: true
412
+ attribute :city, presence: true
413
+ attribute :country, presence: true
414
+ attribute :postal_code, presence: true, format: /.../
415
+ end
416
+ end
417
+
418
+ validator = ShippingDetails.new
419
+ validator.valid? # => false
420
+ ```
421
+
422
+ Bulk operations on errors are guaranteed by `#each`.
423
+ This method yields a **flattened collection of errors**.
424
+
425
+ ```ruby
426
+ validator.errors.each do |error|
427
+ error.name
428
+ # => on the first iteration it returns "full_name"
429
+ # => the second time it returns "address.street" and so on..
430
+ end
431
+ ```
432
+
433
+ Errors for a specific attribute can be accessed via `#for`.
434
+
435
+ ```ruby
436
+ error = validator.errors.for('full_name').first
437
+ error.name # => "full_name"
438
+ error.attribute_name # => "full_name"
439
+
440
+ error = validator.errors.for('address.street').first
441
+ error.name # => "address.street"
442
+ error.attribute_name # => "street"
443
+ ```
444
+
445
+ ### Composable validations
446
+
447
+ Validations can be reused via composition:
448
+
449
+ ```ruby
450
+ require 'hanami/validations'
451
+
452
+ module NameValidations
453
+ include Hanami::Validations
454
+
455
+ attribute :name, presence: true
456
+ end
30
457
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
458
+ module EmailValidations
459
+ include Hanami::Validations
460
+
461
+ attribute :email, presence: true, format: /.../
462
+ end
463
+
464
+ module PasswordValidations
465
+ include Hanami::Validations
466
+
467
+ # We validate only the presence here
468
+ attribute :password, presence: true
469
+ end
470
+
471
+ module CommonValidations
472
+ include EmailValidations
473
+ include PasswordValidations
474
+ end
475
+
476
+ # A valid signup requires:
477
+ # * name (presence)
478
+ # * email (presence and format)
479
+ # * password (presence and confirmation)
480
+ class Signup
481
+ include NameValidations
482
+ include CommonValidations
483
+
484
+ # We decorate PasswordValidations behavior, by requiring the confirmation too.
485
+ # This additional validation is active only in this case.
486
+ attribute :password, confirmation: true
487
+ end
488
+
489
+ # A valid signin requires:
490
+ # * email (presence)
491
+ # * password (presence)
492
+ class Signin
493
+ include CommonValidations
494
+ end
495
+
496
+ # A valid "forgot password" requires:
497
+ # * email (presence)
498
+ class ForgotPassword
499
+ include EmailValidations
500
+ end
501
+ ```
502
+
503
+ ### Complete example
504
+
505
+ ```ruby
506
+ require 'hanami/validations'
507
+
508
+ class Signup
509
+ include Hanami::Validations
510
+
511
+ attribute :first_name, presence: true
512
+ attribute :last_name, presence: true
513
+ attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
514
+ attribute :password, presence: true, confirmation: true, size: 8..64
515
+ end
516
+ ```
517
+
518
+ ### Errors
519
+
520
+ When you invoke `#valid?`, validation errors are available at `#errors`.
521
+ It's a set of errors grouped by attribute. Each error contains the name of the
522
+ invalid attribute, the failed validation, the expected value, and the current one.
523
+
524
+ ```ruby
525
+ require 'hanami/validations'
526
+
527
+ class Signup
528
+ include Hanami::Validations
529
+
530
+ attribute :email, presence: true, format: /\A(.*)@(.*)\.(.*)\z/
531
+ attribute :age, size: 18..99
532
+ end
533
+
534
+ signup = Signup.new(email: 'user@example.org')
535
+ signup.valid? # => true
536
+
537
+ signup = Signup.new(email: '', age: 17)
538
+ signup.valid? # => false
539
+
540
+ signup.errors
541
+ # => #<Hanami::Validations::Errors:0x007fe00ced9b78
542
+ # @errors={
543
+ # :email=>[
544
+ # #<Hanami::Validations::Error:0x007fe00cee3290 @attribute=:email, @validation=:presence, @expected=true, @actual="">,
545
+ # #<Hanami::Validations::Error:0x007fe00cee31f0 @attribute=:email, @validation=:format, @expected=/\A(.*)@(.*)\.(.*)\z/, @actual="">
546
+ # ],
547
+ # :age=>[
548
+ # #<Hanami::Validations::Error:0x007fe00cee30d8 @attribute=:age, @validation=:size, @expected=18..99, @actual=17>
549
+ # ]
550
+ # }>
551
+ ```
552
+
553
+ ### Hanami::Entity
554
+
555
+ Integration with [`Hanami::Entity`](https://github.com/hanami/model) is straight forward.
556
+
557
+ ```ruby
558
+ require 'hanami/model'
559
+ require 'hanami/validations'
560
+
561
+ class Product
562
+ include Hanami::Entity
563
+ include Hanami::Validations
564
+
565
+ attribute :name, type: String, presence: true
566
+ attribute :price, type: Integer, presence: true
567
+ end
568
+
569
+ product = Product.new(name: 'Book', price: '100')
570
+ product.valid? # => true
571
+
572
+ product.name # => "Book"
573
+ product.price # => 100
574
+ ```
32
575
 
33
576
  ## Contributing
34
577
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hanami-validations.
578
+ 1. Fork it ( https://github.com/hanami/hanami-validations/fork )
579
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
580
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
581
+ 4. Push to the branch (`git push origin my-new-feature`)
582
+ 5. Create a new Pull Request
583
+
584
+ ## Copyright
585
+
586
+ Copyright © 2014-2016 Luca Guidi – Released under MIT License
36
587
 
588
+ This project was formerly known as Lotus (`lotus-validations`).