Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dogweather/validated_object
Self-validating Ruby objects
https://github.com/dogweather/validated_object
activemodel gem rails-validations ruby strongly-typed
Last synced: 2 months ago
JSON representation
Self-validating Ruby objects
- Host: GitHub
- URL: https://github.com/dogweather/validated_object
- Owner: dogweather
- License: mit
- Created: 2015-08-18T03:18:46.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2024-05-02T15:15:12.000Z (8 months ago)
- Last Synced: 2024-10-14T00:25:38.640Z (3 months ago)
- Topics: activemodel, gem, rails-validations, ruby, strongly-typed
- Language: Ruby
- Homepage:
- Size: 175 KB
- Stars: 63
- Watchers: 4
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: HISTORY.md
- License: LICENSE.txt
Awesome Lists containing this project
README
[![Gem Version](https://badge.fury.io/rb/validated_object.svg)](https://badge.fury.io/rb/validated_object) [![Code Climate](https://codeclimate.com/github/dogweather/validated_object/badges/gpa.svg)](https://codeclimate.com/github/dogweather/validated_object)
# ValidatedObject
`Plain Old Ruby` + `Rails Validations` = **self-checking Ruby objects**.
## Example: A `Person` class that ensures its `name` isn't blank (nil or empty string):
```ruby
class Person < ValidatedObject::Base
attr_reader :name
validates :name, presence: true
end# Instantiating it runs the validations.
me = Person.new(name: 'Robb')
you = Person.new(name: '') # => ArgumentError: "Name can't be blank"
```Note how Person's two lines of code are nothing new: `attr_reader` is standard Ruby. [`validates`](https://guides.rubyonrails.org/active_record_validations.html) is standard Rails. I use classes like these as Data Transfer Objects at my system boundaries.
## Goals
* Very readable error messages
* Clean, minimal syntaxThis is a small layer around
[ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates). (About 25 lines of code.) So if you know how to use [Rails Validations](https://guides.rubyonrails.org/active_record_validations.html), you're good to go. I wrote this to help with CSV data imports and [website structured data](https://github.com/dogweather/schema-dot-org).## Usage
### Writing a self-validating object
All of the [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates) are available, plus a new one, `TypeValidator`.
```ruby
class Dog < ValidatedObject::Base
# Plain old Ruby
attr_accessor :name, :birthday# Plain old Rails
validates :name, presence: true
# A new type-validation if you'd like to use it
validates :birthday, type: Date, allow_nil: true # Strongly typed but optional
end
```Alternatively, we could make it immutable with Ruby's [attr_reader](https://bootrails.com/blog/ruby-attr-accessor-attr-writer-attr-reader/#2-attr_reader-attr_writer--attr_accessor):
```ruby
class ImmutableDog < ValidatedObject::Base
attr_reader :name, :birthdayvalidates :name, presence: true
validates :birthday, type: Date, allow_nil: true
end
```And again, that `ImmutableDog` consists of one line of plain Ruby and two lines of standard Rails validations.
### `attr_reader` followed by `validates` is such a common pattern that there's a DSL which wraps them up into one call: `validates_attr`.
Here's the immutable version of `Dog` re-written with the new, simplified DSL:
```ruby
class ImmutableDog < ValidatedObject::Base
validates_attr :name, presence: true
validates_attr :birthday, type: Date, allow_nil: true
end
```### About that `type:` check
The included `TypeValidator` is what enables `type: Date`, above. All classes can be checked, as well as a pseudo-class `Boolean`. E.g.:
```ruby
#...
validates :premium_membership, type: Boolean
#...
```### Instantiating and automatically validating
```ruby
# This Dog instance validates itself at the end of instantiation.
spot = Dog.new(name: 'Spot')
``````ruby
# We can also explicitly test for validity because all of
# ActiveModel::Validations is available.
spot.valid? # => truespot.birthday = Date.new(2015, 1, 23)
spot.valid? # => true
```### Good error messages
Any of the standard Validations methods can be
used to test an instance, plus the custom `check_validations!` convenience method:```ruby
spot.birthday = '2015-01-23'
spot.valid? # => false
spot.check_validations! # => ArgumentError: Birthday is a String, not a Date
```Note the clear, explicit error message. These are great when reading a log
file following a data import. It describes all the invalid conditions. Let's
test it by making another attribute invalid:```ruby
spot.name = nil
spot.check_validations! # => ArgumentError: Name can't be blank; Birthday is a String, not a Date
```### Use in parsing data
I often use a validated object in a loop to import data, e.g.:
```ruby
# Import a CSV file of dogs
dogs = []
csv.next_row do |row|
begin
dogs << Dog.new(name: row.name)
rescue ArgumentError => e
logger.warn(e)
end
end
```The result is that `dogs` is an array of guaranteed valid Dog objects. And the
error log lists unparseable rows with good info for tracking down problems in
the data.### Use in code generation
My [Schema.org structured data gem](https://github.com/dogweather/schema-dot-org) uses ValidatedObjects to recursively create well formed HTML / JSON-LD.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'validated_object'
```And then execute:
$ bundle
Or install it yourself as:
$ gem install validated_object
## Development
(TODO: Verify these instructions.) After checking out the repo, run `bin/setup`
to install dependencies. Then, run `rake spec` to run the tests. You can also
run `bin/console` for an interactive prompt that will allow you to experiment.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).## Contributing
Bug reports and pull requests are welcome on GitHub.
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).