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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: beeec5e7c798a88c65b4f5a492ce3e59505dacf6a0a1f8de4da90ca59c73f873
4
- data.tar.gz: 3c18ec02b076c71a020eaf7825fa2014321e09ee43a5490373698bfd8deb3c59
3
+ metadata.gz: cbb448bc227821b65819e57ae210f715ea5295bf4c7f2e14925e560340a56a38
4
+ data.tar.gz: 7e78815f3603aedfe4e4eda9cf5e626a64d0ef91f3f237b78a13e110697ce999
5
5
  SHA512:
6
- metadata.gz: 279331de46a2f201ee2eafcb1633ab0ad3b428fa7651276e7754a4e06b6a740f1c473fd14e6296d428d74e3ee39c962bdbcc0e0ebaf6f7bbc7a7fdd393bc56c1
7
- data.tar.gz: afe9a3252da50c7bd028ebbfec81729e0ecf71e0c8c5ff1272d31e616593d41e031a87b11602cfb0337dac3c21d0abad1af024007757c3cab462df66c79fa163
6
+ metadata.gz: 75745c4db0c873e4a4a5f63ca792a8646abcf5402408d0824e9a704e11112d91c5c303de4a4cf6addffd61ed9532f7327f602442c10ab4969b9332a6e3b6e161
7
+ data.tar.gz: 4fa2b7800b2675469d85d5ce9a69f5bf2683fc56376f2bfa0fb623fd0491ad2d1c0833d44f55e124ebf067cc04066a5afd3f7d9ad6ea9d76d87ae00f917b770e
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.2
4
- - 2.3.1
3
+ - 2.6.6
5
4
  - 2.7.1
6
5
  before_install: gem install bundler
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 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).
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 # attr_reader is supported as well for read-only attributes
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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module ValidatedObject
5
- VERSION = '2.1.0'
5
+ VERSION = '2.3.0'
6
6
  end
@@ -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).returns(ValidatedObject::Base)}
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
- self
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.1.0
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: 2020-09-04 00:00:00.000000000 Z
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.1.4
143
+ rubygems_version: 3.4.20
143
144
  signing_key:
144
145
  specification_version: 4
145
146
  summary: Self-validating plain Ruby objects.