validated_object 2.1.0 → 2.3.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 +4 -4
- data/.travis.yml +1 -2
- data/README.md +40 -2
- data/lib/validated_object/simplified_api.rb +18 -0
- data/lib/validated_object/version.rb +1 -1
- data/lib/validated_object.rb +15 -7
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbb448bc227821b65819e57ae210f715ea5295bf4c7f2e14925e560340a56a38
|
4
|
+
data.tar.gz: 7e78815f3603aedfe4e4eda9cf5e626a64d0ef91f3f237b78a13e110697ce999
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75745c4db0c873e4a4a5f63ca792a8646abcf5402408d0824e9a704e11112d91c5c303de4a4cf6addffd61ed9532f7327f602442c10ab4969b9332a6e3b6e161
|
7
|
+
data.tar.gz: 4fa2b7800b2675469d85d5ce9a69f5bf2683fc56376f2bfa0fb623fd0491ad2d1c0833d44f55e124ebf067cc04066a5afd3f7d9ad6ea9d76d87ae00f917b770e
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,19 @@
|
|
3
3
|
# ValidatedObject
|
4
4
|
|
5
5
|
Plain Old Ruby Objects + Rails Validations = **self-checking Ruby objects**.
|
6
|
+
Here's a quick example of a common case: a class with an immutable,
|
7
|
+
required, type-checked attribute:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Person < ValidatedObject::Base
|
11
|
+
validated_attr :name, type: String, presence: true
|
12
|
+
end
|
13
|
+
|
14
|
+
# Using it
|
15
|
+
me = Person.new(name: 'Robb')
|
16
|
+
```
|
17
|
+
|
18
|
+
I use classes like these as Data Transfer Objects at my system boundaries.
|
6
19
|
|
7
20
|
|
8
21
|
## Goals
|
@@ -11,7 +24,7 @@ Plain Old Ruby Objects + Rails Validations = **self-checking Ruby objects**.
|
|
11
24
|
* Clean, minimal syntax
|
12
25
|
|
13
26
|
This is a small layer around
|
14
|
-
[ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates). (About
|
27
|
+
[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, 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).
|
15
28
|
|
16
29
|
|
17
30
|
## Usage
|
@@ -24,7 +37,7 @@ All of the [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveM
|
|
24
37
|
```ruby
|
25
38
|
class Dog < ValidatedObject::Base
|
26
39
|
# Plain old Ruby
|
27
|
-
attr_accessor :name, :birthday
|
40
|
+
attr_accessor :name, :birthday
|
28
41
|
|
29
42
|
# Plain old Rails
|
30
43
|
validates :name, presence: true
|
@@ -34,6 +47,31 @@ class Dog < ValidatedObject::Base
|
|
34
47
|
end
|
35
48
|
```
|
36
49
|
|
50
|
+
We can make it immutable with `attr_reader`:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class ImmutableDog < ValidatedObject::Base
|
54
|
+
attr_reader :name, :birthday
|
55
|
+
|
56
|
+
validates :name, presence: true
|
57
|
+
validates :birthday, type: Date, allow_nil: true
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
> `attr_reader` followed by `validates` is such a common pattern that
|
62
|
+
> there's a second DSL which wraps them up into one call: `validates_attr`.
|
63
|
+
|
64
|
+
Here's the immutable version of `Dog` re-written with the simplified DSL:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
class ImmutableDog < ValidatedObject::Base
|
68
|
+
validates_attr :name, presence: true
|
69
|
+
validates_attr :birthday, type: Date, allow_nil: true
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
### About that `type:` check
|
74
|
+
|
37
75
|
The included `TypeValidator` is what enables `type: Date`, above. All classes can be checked, as well as a pseudo-class `Boolean`. E.g.:
|
38
76
|
|
39
77
|
```ruby
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
# Enable a simplified API for the common case of
|
4
|
+
# read-only ValidatedObjects.
|
5
|
+
module ValidatedObject
|
6
|
+
module SimplifiedApi
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
# Simply delegate to `attr_reader` and `validates`.
|
11
|
+
def validated_attr(attribute, *options)
|
12
|
+
attr_reader attribute
|
13
|
+
validates attribute, *options
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/validated_object.rb
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
require 'active_model'
|
5
5
|
require 'sorbet-runtime'
|
6
6
|
require 'validated_object/version'
|
7
|
+
require 'validated_object/simplified_api'
|
8
|
+
|
7
9
|
|
8
10
|
module ValidatedObject
|
9
11
|
# @abstract Subclass and add `attr_accessor` and validations
|
@@ -43,6 +45,7 @@ module ValidatedObject
|
|
43
45
|
# @see http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html Rails 3.0′s ActiveModel: How To Give Ruby Classes Some ActiveRecord Magic, Peter Cooper
|
44
46
|
class Base
|
45
47
|
include ActiveModel::Validations
|
48
|
+
include SimplifiedApi
|
46
49
|
extend T::Sig
|
47
50
|
|
48
51
|
SymbolHash = T.type_alias { T::Hash[Symbol, T.untyped] }
|
@@ -63,18 +66,23 @@ module ValidatedObject
|
|
63
66
|
#
|
64
67
|
# @raise [ArgumentError] if the object is not valid at the
|
65
68
|
# end of initialization or `attributes` is not a Hash.
|
66
|
-
sig { params(attributes: SymbolHash).
|
69
|
+
sig { params(attributes: SymbolHash).void }
|
67
70
|
def initialize(attributes = EMPTY_HASH)
|
68
71
|
set_instance_variables from_hash: attributes
|
69
72
|
check_validations!
|
70
|
-
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def validated_attr(attribute_name, **validation_options)
|
77
|
+
attr_reader attribute_name
|
78
|
+
validates attribute_name, validation_options
|
71
79
|
end
|
72
80
|
|
73
81
|
# Run any validations and raise an error if invalid.
|
74
82
|
#
|
75
83
|
# @raise [ArgumentError] if any validations fail.
|
76
84
|
# @return [ValidatedObject::Base] the receiver
|
77
|
-
sig {returns(ValidatedObject::Base)}
|
85
|
+
sig { returns(ValidatedObject::Base) }
|
78
86
|
def check_validations!
|
79
87
|
raise ArgumentError, errors.full_messages.join('; ') if invalid?
|
80
88
|
|
@@ -118,17 +126,17 @@ module ValidatedObject
|
|
118
126
|
|
119
127
|
private
|
120
128
|
|
121
|
-
sig {params(expected_class: T.untyped, value: T.untyped).returns(T.untyped)}
|
129
|
+
sig { params(expected_class: T.untyped, value: T.untyped).returns(T.untyped) }
|
122
130
|
def pseudo_boolean?(expected_class, value)
|
123
131
|
expected_class == Boolean && boolean?(value)
|
124
132
|
end
|
125
133
|
|
126
|
-
sig {params(expected_class: T.untyped, value: T.untyped).returns(T.untyped)}
|
134
|
+
sig { params(expected_class: T.untyped, value: T.untyped).returns(T.untyped) }
|
127
135
|
def expected_class?(expected_class, value)
|
128
136
|
value.is_a?(expected_class)
|
129
137
|
end
|
130
138
|
|
131
|
-
sig {params(value: T.untyped).returns(T.untyped)}
|
139
|
+
sig { params(value: T.untyped).returns(T.untyped) }
|
132
140
|
def boolean?(value)
|
133
141
|
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
134
142
|
end
|
@@ -150,7 +158,7 @@ module ValidatedObject
|
|
150
158
|
|
151
159
|
private
|
152
160
|
|
153
|
-
sig {params(from_hash: SymbolHash).void}
|
161
|
+
sig { params(from_hash: SymbolHash).void }
|
154
162
|
def set_instance_variables(from_hash:)
|
155
163
|
from_hash.each do |variable_name, variable_value|
|
156
164
|
# Test for the attribute reader
|
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: 2.
|
4
|
+
version: 2.3.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: 2023-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- bin/console
|
99
99
|
- bin/setup
|
100
100
|
- lib/validated_object.rb
|
101
|
+
- lib/validated_object/simplified_api.rb
|
101
102
|
- lib/validated_object/version.rb
|
102
103
|
- script/demo.rb
|
103
104
|
- sorbet/config
|
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
140
|
- !ruby/object:Gem::Version
|
140
141
|
version: '0'
|
141
142
|
requirements: []
|
142
|
-
rubygems_version: 3.
|
143
|
+
rubygems_version: 3.4.20
|
143
144
|
signing_key:
|
144
145
|
specification_version: 4
|
145
146
|
summary: Self-validating plain Ruby objects.
|