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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 97d91eb8801c44a0daecab2f6bf5e66c1dc34908
4
- data.tar.gz: b53ae1848ed9176217969907ff95d4ceb6f0d06b
2
+ SHA256:
3
+ metadata.gz: ba509cb442a5ef4c67d7186bd58b329551c00e137ec2c2b1cd7c4e268b92344a
4
+ data.tar.gz: 79a4f93be0f9919bf189f01258ed0379382df90aa01bc69a5ae883d924d53527
5
5
  SHA512:
6
- metadata.gz: 7df6a6cacb4a691183fe606828b572a74e08b139d136e8e6826e5fd2ff3f441443b2f4ef451da96a65040075a46ecfee7e123da9f1ed911308c26b586e0482fe
7
- data.tar.gz: 86ff719a5c3f23f76f843c049a1071b5ff79e6b20953ca482a3cedf33904adde167553d6efce284e067a0f69bb3841534f1bceb2d29a6bd01ed1dacd77bd8931
6
+ metadata.gz: d626a9f7e53258a92e5a0fa3a8cfabf4c7ba38e2c960466e29aaf98dacb7e433c02e3facaca3d2c96a3bd769077a3c3d6e1378b9631a48b6e307db88c8b91f98
7
+ data.tar.gz: 73771320ac4176387bbe336057c2459b5772898a68b380518e149f93af8a29243312462adda6f498a15fb777cb8e803e0db684bc41c130fc316135b63dcc9dac
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1
4
3
  - 2.2.2
4
+ - 2.3.1
5
5
  before_install: gem install bundler -v 1.10.6
data/README.md CHANGED
@@ -2,78 +2,133 @@
2
2
 
3
3
  # ValidatedObject
4
4
 
5
- Uses
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
- ## Installation
8
+ ## Goals
12
9
 
13
- Add this line to your application's Gemfile:
10
+ * Very readable error messages
11
+ * Clean, minimal syntax
14
12
 
15
- ```ruby
16
- gem 'validated_object'
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
- # The dog1 instance validates itself at the end of instantiation.
47
- # Here, it succeeds and so doesn't raise an exception.
48
- dog1 = Dog.new do |d|
49
- d.name = 'Spot'
50
- end
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
- # We can also explicitly test for validity
53
- dog1.valid? # => true
57
+ ### Good error messages
54
58
 
55
- dog1.birthday = Date.new(2015, 1, 23)
56
- dog1.valid? # => true
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
- ### Making an instance _invalid_
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
- dog1.birthday = '2015-01-23'
63
- dog1.valid? # => false
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` 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.
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 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).
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 https://github.com/dogweather/validated_object.
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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ValidatedObject
2
- VERSION = '1.1.0'.freeze
3
+ VERSION = '2.0.0'.freeze
3
4
  end
@@ -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 do |d|
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
- # @yieldparam [ValidatedObject] new_object the yielded new object
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
- yield(self)
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 class #{value.class}, not #{expected_class}"
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: 1.1.0
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: 2016-04-13 00:00:00.000000000 Z
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.5.0
111
+ rubygems_version: 2.7.6
111
112
  signing_key:
112
113
  specification_version: 4
113
114
  summary: Self-validating plain Ruby objects.