validated_object 1.1.0 → 2.0.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 +5 -5
- data/.travis.yml +1 -1
- data/README.md +90 -35
- data/lib/validated_object/version.rb +2 -1
- data/lib/validated_object.rb +15 -12
- data/script/demo.rb +17 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ba509cb442a5ef4c67d7186bd58b329551c00e137ec2c2b1cd7c4e268b92344a
|
4
|
+
data.tar.gz: 79a4f93be0f9919bf189f01258ed0379382df90aa01bc69a5ae883d924d53527
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d626a9f7e53258a92e5a0fa3a8cfabf4c7ba38e2c960466e29aaf98dacb7e433c02e3facaca3d2c96a3bd769077a3c3d6e1378b9631a48b6e307db88c8b91f98
|
7
|
+
data.tar.gz: 73771320ac4176387bbe336057c2459b5772898a68b380518e149f93af8a29243312462adda6f498a15fb777cb8e803e0db684bc41c130fc316135b63dcc9dac
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,78 +2,133 @@
|
|
2
2
|
|
3
3
|
# ValidatedObject
|
4
4
|
|
5
|
-
|
6
|
-
[ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates)
|
7
|
-
to create self-validating Plain Old Ruby objects. I wrote it for helping with CSV data imports into my Rails apps.
|
8
|
-
Very readable error messages are also important in that context, to track down parsing errors. This gem provides those too.
|
5
|
+
Plain Old Ruby Objects + Rails Validations = self-checking Ruby objects.
|
9
6
|
|
10
7
|
|
11
|
-
##
|
8
|
+
## Goals
|
12
9
|
|
13
|
-
|
10
|
+
* Very readable error messages
|
11
|
+
* Clean, minimal syntax
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
```
|
13
|
+
This is a small layer around
|
14
|
+
[ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates). (About 18 lines of code.) So if you know how to use Rails Validations, you're good to go. I wrote this to help with CSV data imports and [website microdata generation](https://github.com/dogweather/schema-dot-org).
|
18
15
|
|
19
|
-
And then execute:
|
20
|
-
|
21
|
-
$ bundle
|
22
|
-
|
23
|
-
Or install it yourself as:
|
24
|
-
|
25
|
-
$ gem install validated_object
|
26
16
|
|
27
17
|
## Usage
|
28
18
|
|
29
19
|
|
30
20
|
### Writing a self-validating object
|
31
21
|
|
32
|
-
All of the [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates) are available, plus a new one, `TypeValidator`.
|
22
|
+
All of the [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates) are available, plus a new one, `TypeValidator`.
|
33
23
|
|
34
24
|
```ruby
|
35
25
|
class Dog < ValidatedObject::Base
|
36
|
-
attr_accessor :name, :birthday
|
26
|
+
attr_accessor :name, :birthday # attr_reader is supported as well for read-only attributes
|
37
27
|
|
38
28
|
validates :name, presence: true
|
39
|
-
validates :birthday, type: Date, allow_nil: true
|
29
|
+
validates :birthday, type: Date, allow_nil: true # Strongly typed but optional
|
40
30
|
end
|
41
31
|
```
|
42
32
|
|
33
|
+
The `TypeValidator` is what enables `type: Date`, above. All classes can be checked, as well as a pseudo-class `Boolean`. E.g.:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
#...
|
37
|
+
validates :premium_membership, type: Boolean
|
38
|
+
#...
|
39
|
+
```
|
40
|
+
|
43
41
|
### Instantiating and automatically validating
|
44
42
|
|
45
43
|
```ruby
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
# This Dog instance validates itself at the end of instantiation.
|
45
|
+
spot = Dog.new(name: 'Spot')
|
46
|
+
```
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
# We can also explicitly test for validity because all of
|
50
|
+
# ActiveModel::Validations is available.
|
51
|
+
spot.valid? # => true
|
52
|
+
|
53
|
+
spot.birthday = Date.new(2015, 1, 23)
|
54
|
+
spot.valid? # => true
|
55
|
+
```
|
51
56
|
|
52
|
-
|
53
|
-
dog1.valid? # => true
|
57
|
+
### Good error messages
|
54
58
|
|
55
|
-
|
56
|
-
|
59
|
+
Any of the standard Validations methods can be
|
60
|
+
used to test an instance, plus the custom `check_validations!` convenience method:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
spot.birthday = '2015-01-23'
|
64
|
+
spot.valid? # => false
|
65
|
+
spot.check_validations! # => ArgumentError: Birthday is class String, not Date
|
57
66
|
```
|
58
67
|
|
59
|
-
|
68
|
+
Note the clear, explicit error message. These are great when reading a log
|
69
|
+
file following a data import. It describes all the invalid conditions. Let's
|
70
|
+
test it by making another attribute invalid:
|
60
71
|
|
61
72
|
```ruby
|
62
|
-
|
63
|
-
|
64
|
-
dog1.check_validations! # => ArgumentError: Birthday is class String, not Date
|
73
|
+
spot.name = nil
|
74
|
+
spot.check_validations! # => ArgumentError: Name can't be blank; Birthday is class String, not Date
|
65
75
|
```
|
66
76
|
|
67
77
|
|
78
|
+
### Use in parsing data
|
79
|
+
|
80
|
+
I often use a validated object in a loop to import data, e.g.:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# Import a CSV file of dogs
|
84
|
+
dogs = []
|
85
|
+
csv.next_row do |row|
|
86
|
+
begin
|
87
|
+
dogs << Dog.new(name: row.name)
|
88
|
+
rescue ArgumentError => e
|
89
|
+
logger.warn(e)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
The result is that `dogs` is an array of guaranteed valid Dog objects. And the
|
95
|
+
error log lists unparseable rows with good info for tracking down problems in
|
96
|
+
the data.
|
97
|
+
|
98
|
+
## Installation
|
99
|
+
|
100
|
+
Add this line to your application's Gemfile:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
gem 'validated_object'
|
104
|
+
```
|
105
|
+
|
106
|
+
And then execute:
|
107
|
+
|
108
|
+
$ bundle
|
109
|
+
|
110
|
+
Or install it yourself as:
|
111
|
+
|
112
|
+
$ gem install validated_object
|
113
|
+
|
114
|
+
|
115
|
+
|
68
116
|
## Development
|
69
117
|
|
70
|
-
(TODO: Verify these instructions.) After checking out the repo, run `bin/setup`
|
118
|
+
(TODO: Verify these instructions.) After checking out the repo, run `bin/setup`
|
119
|
+
to install dependencies. Then, run `rake spec` to run the tests. You can also
|
120
|
+
run `bin/console` for an interactive prompt that will allow you to experiment.
|
71
121
|
|
72
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To
|
122
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
123
|
+
release a new version, update the version number in `version.rb`, and then run
|
124
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
125
|
+
git commits and tags, and push the `.gem` file to
|
126
|
+
[rubygems.org](https://rubygems.org).
|
73
127
|
|
74
128
|
## Contributing
|
75
129
|
|
76
|
-
Bug reports and pull requests are welcome on GitHub at
|
130
|
+
Bug reports and pull requests are welcome on GitHub at
|
131
|
+
https://github.com/dogweather/validated_object.
|
77
132
|
|
78
133
|
|
79
134
|
## License
|
data/lib/validated_object.rb
CHANGED
@@ -21,9 +21,7 @@ module ValidatedObject
|
|
21
21
|
# @example Instantiating and automatically validating
|
22
22
|
# # The dog1 instance validates itself at the end of instantiation.
|
23
23
|
# # Here, it succeeds and so doesn't raise an exception.
|
24
|
-
# dog1 = Dog.new
|
25
|
-
# d.name = 'Spot'
|
26
|
-
# end
|
24
|
+
# dog1 = Dog.new name: 'Spot'
|
27
25
|
#
|
28
26
|
# # We can also explicitly test for validity
|
29
27
|
# dog1.valid? # => true
|
@@ -42,19 +40,24 @@ module ValidatedObject
|
|
42
40
|
class Base
|
43
41
|
include ActiveModel::Validations
|
44
42
|
|
43
|
+
EMPTY_HASH = {}.freeze
|
44
|
+
|
45
45
|
# Implements a pseudo-boolean class.
|
46
46
|
class Boolean
|
47
47
|
end
|
48
48
|
|
49
49
|
# Instantiate and validate a new object.
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# for configuration.
|
50
|
+
# @example
|
51
|
+
# maru = Dog.new(birthday: Date.today, name: 'Maru')
|
53
52
|
#
|
54
53
|
# @raise [ArgumentError] if the object is not valid at the
|
55
|
-
# end of initialization.
|
56
|
-
def initialize
|
57
|
-
|
54
|
+
# end of initialization or `attributes` is not a Hash.
|
55
|
+
def initialize(attributes=EMPTY_HASH)
|
56
|
+
raise ArgumentError, "#{attributes} is not a Hash" unless attributes.is_a?(Hash)
|
57
|
+
|
58
|
+
attributes.keys.each do |key|
|
59
|
+
self.instance_variable_set "@#{key}".to_sym, attributes.fetch(key)
|
60
|
+
end
|
58
61
|
check_validations!
|
59
62
|
self
|
60
63
|
end
|
@@ -73,8 +76,8 @@ module ValidatedObject
|
|
73
76
|
# @example Ensure that weight is a number
|
74
77
|
# class Dog < ValidatedObject::Base
|
75
78
|
# attr_accessor :weight, :neutered
|
76
|
-
# validates :weight, type: Numeric
|
77
|
-
# validates :neutered, type: Boolean
|
79
|
+
# validates :weight, type: Numeric # Typed and required
|
80
|
+
# validates :neutered, type: Boolean, allow_nil: true # Typed but optional
|
78
81
|
# end
|
79
82
|
class TypeValidator < ActiveModel::EachValidator
|
80
83
|
# @return [nil]
|
@@ -87,7 +90,7 @@ module ValidatedObject
|
|
87
90
|
return if value.is_a?(expected_class)
|
88
91
|
end
|
89
92
|
|
90
|
-
msg = options[:message] || "is
|
93
|
+
msg = options[:message] || "is a #{value.class}, not a #{expected_class}"
|
91
94
|
record.errors.add attribute, msg
|
92
95
|
end
|
93
96
|
end
|
data/script/demo.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'validated_object'
|
3
|
+
|
4
|
+
class Dog < ValidatedObject::Base
|
5
|
+
attr_reader :name, :birthday
|
6
|
+
validates :name, presence: true
|
7
|
+
validates :birthday, type: Date, allow_nil: true
|
8
|
+
end
|
9
|
+
|
10
|
+
phoebe = Dog.new(name: 'Phoebe')
|
11
|
+
puts phoebe.inspect
|
12
|
+
|
13
|
+
maru = Dog.new(birthday: Date.today, name: 'Maru')
|
14
|
+
puts maru.inspect
|
15
|
+
|
16
|
+
paris = Dog.new
|
17
|
+
puts paris.inspect
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: validated_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robb Shecter
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- bin/setup
|
86
86
|
- lib/validated_object.rb
|
87
87
|
- lib/validated_object/version.rb
|
88
|
+
- script/demo.rb
|
88
89
|
- validated_object.gemspec
|
89
90
|
homepage: https://github.com/dogweather/validated_object
|
90
91
|
licenses:
|
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
108
|
version: '0'
|
108
109
|
requirements: []
|
109
110
|
rubyforge_project:
|
110
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.7.6
|
111
112
|
signing_key:
|
112
113
|
specification_version: 4
|
113
114
|
summary: Self-validating plain Ruby objects.
|