Lotus::Validations

Validation mixin for Ruby objects

19/08/15

James N.

What does the gem do?

The gem basically does three things:

1) Defines an accessor


require 'lotus/validations'

class Person
  include Lotus::Validations

  attribute :name,  presence: true
end

person = Person.new(name: 'Luca')
person.name  # => "Luca"
person.email   # => raises NoMethodError
					

2) Provides #valid?


class Person
  include Lotus::Validations

  attribute :fave_food, format: /cake/
end

person = Person.new(fave_food: 'tears')
person.valid?
# => false
					

3) Provides #errors


person = Person.new(fave_food: 'tears')
person.valid?
# => false
person.errors.inspect
# => "#<Lotus::Validations::Errors:0x00000001351140 @errors={
#  :fave_food=>[
#    #<Lotus::Validations::Error:0x00000001350fd8
#    @attribute_name=\"fave_food\",
#    @validation=:format,
#    @expected=/cake/,
#    @actual=\"tears\",
#    @namespace=nil,
#    @attribute=\"fave_food\">]
#  }>"
					

Coercions

You can specify a type on your attribute definitions. Assignments will then be coerced, if possible.


class Person
  include Lotus::Validations

  attribute :fav_number, type: Integer
  # Or: Array   BigDecimal  Boolean  Date      DateTime
  #     Float   Hash        Integer  Pathname  Set
  #     String  Symbol      Time
end

person = Person.new(fav_number: '23')
person.valid?

person.fav_number # => 23
					

Custom Coercions

You can define your own coercion classes.


class FavNumber
  # The constructor of a class used for type coercion must
  # have an arity of one.
  def initialize(number)
    @number = number
  end
end

class Person
  include Lotus::Validations

  attribute :fav_number, type: FavNumber
end

person = Person.new(fav_number: '23')
person.fav_number # => #<FavNumber:0x007ffc644bba00 @number="23">
					

Validations (surprisingly)

Validations are triggered when you invoke #valid?

There are a bunch of them.

Acceptance


attribute :terms_of_service, acceptance: true
					

An attribute is valid if its value is truthy.

Confirmation


attribute :password, confirmation: true
					

An attribute is valid if its value and the value of a corresponding attribute is valid.

By convention, if you have a password attribute, the validation looks for password_confirmation.

Exclusion


attribute :pleasant_languages, exclusion: ['c', 'prolog']
					

Returns false if the attribute value is `#include?`ed in the exclusion list.

Inclusion


attribute :age, inclusion: 18..99
					

The opposite of exclusion.

Format


attribute :name, format: /\A[a-zA-Z]+\z/
					

An attribute is valid if it matches the given regex.

Presence


attribute :name, presence: true
					

An attribute is valid if present.

Returns false even if attribute explicitly set to `nil`

“Showing up is 80 percent of life.” - Woody Allen

Size


attribute :ssn,      size: 11    # exact match
attribute :password, size: 8..64 # range
  					

Uniqueness

An attribute is valid if... uh.

This gem doesn't actually support uniqueness validations.

Any code-level uniqueness test will be subject to race conditions.

“Your relational database is designed to enforce data integrity; let it.”

Thanks!

Unfortunately there's not much to say about this gem.

It's pretty small, does one thing, and seems to do it pretty well.

If I had more time, I would have liked to try defining custom validations.

Links

github:lotus/validations

The Perils of Uniqueness Validations - Thoughtbot