hatch 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +52 -16
- data/hatch.gemspec +1 -1
- data/lib/hatch.rb +30 -7
- data/test/common_validations_test.rb +3 -5
- data/test/errors_test.rb +27 -0
- data/test/validation_test.rb +3 -19
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzJjNWMxMjRlMzM0OGM0YTk2YWY3MmQ5YjAyZWNiMDZjYjg1YWQ0OA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzJhNTQyYjJhMTUyOWZmOWE1OTdjMzY2ZDZmMDQ0MmViY2Y5ODEzZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTY4NzUzN2Y3OGYyMWFlYmVmNGVjMTI1NDg5Yjc0Y2JiOGY2YmM4NWQyY2Fm
|
10
|
+
OTFlMTc0Y2Q5ZWE0YmFhODJkNTc4YWY3YjNhMmQ1MDU3ZWQyNzI1ZmIxZmFk
|
11
|
+
ZjA4ZDNlODYwMmY0NTgzMmQyYTY1YTFiMzQwNDc3YzBkMTVlYzY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
M2E5M2QyNzE3YjE1NDRmZWM4MDAzNDg2ZjU1ZmY4YTNhMjRkODcxZjc1Yzg2
|
14
|
+
MmQyMGM4NzY0ZTU1NjIwNGQzNDlkNzc5MmQ4NTFhNjY5MzY3NjhiYmFiMTBk
|
15
|
+
ODQ5M2IwNjI0ZjYzNDdhN2MyMzQ5MWMzODBiNDg1ZWI5M2JjNTU=
|
data/README.md
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
Hatch
|
2
2
|
=====
|
3
3
|
|
4
|
+
Installation
|
5
|
+
------------
|
6
|
+
|
7
|
+
$ gem install hatch
|
8
|
+
|
9
|
+
Usage
|
10
|
+
-----
|
11
|
+
|
4
12
|
An address without a street? A person without a name? Those are not valid objects!
|
5
13
|
Why should you have them hanging around your system?
|
6
14
|
|
7
|
-
Tell
|
8
|
-
the
|
15
|
+
Tell `Hatch` how to certify the attributes of your models, and he will give you
|
16
|
+
the appropriate object.
|
9
17
|
|
10
18
|
If you don't hatch your model with all the correct attributes, it will give you
|
11
19
|
an object representing an invalid instance of it.
|
@@ -29,38 +37,66 @@ end
|
|
29
37
|
address = Address.hatch(street: 'Fake St', number: 1234)
|
30
38
|
address.class
|
31
39
|
# => Address
|
40
|
+
address.valid?
|
41
|
+
# => true
|
32
42
|
|
33
43
|
not_an_address = Address.hatch(street: '', number: 1234)
|
34
44
|
not_an_address.class
|
35
45
|
# => Address::InvalidAddress
|
46
|
+
not_an_address.valid?
|
47
|
+
# => false
|
36
48
|
```
|
37
49
|
|
38
|
-
You declare your attributes to
|
39
|
-
then use
|
50
|
+
You declare your attributes to `Hatch` with the `attributes` message and
|
51
|
+
then use `certify(:attribute, 'error message', &validation)` to verify when an
|
40
52
|
attribute is valid.
|
41
53
|
|
42
|
-
|
43
|
-
|
54
|
+
In case you're wondering, the `Model::InvalidModel` is polymorphic with your
|
55
|
+
`Model` in all the reader methods declared by `attr_reader` or `attr_accessor`
|
56
|
+
|
57
|
+
`Hatch` also supports some common validations we all like to have! You can pass an error
|
58
|
+
of your own or just use the default.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
class Address
|
62
|
+
include Hatch
|
63
|
+
attributes :street, :number
|
64
|
+
|
65
|
+
certifies(:street, :presence, "This is an error! Where's my street?!")
|
66
|
+
certifies(:number, :positive_number)
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
Common validations come in the following flavours (along with default errors)
|
71
|
+
|
72
|
+
* `:presence` - `"must be present"`
|
73
|
+
* `:positive_number` - `"must be a positive number"`
|
74
|
+
|
75
|
+
Aaand that's it for the moment. I'll keep on adding more as they come to my mind. If they come
|
76
|
+
to yours first, feel free to add them and PR.
|
77
|
+
|
78
|
+
Errors
|
79
|
+
------
|
80
|
+
|
81
|
+
You'll also get a handy `errors` hash with a couple of super powers.
|
44
82
|
|
45
83
|
```ruby
|
46
84
|
not_an_address = Address.hatch(street: '', number: 1234)
|
47
85
|
not_an_address.class
|
48
86
|
# => Address::InvalidAddress
|
49
87
|
|
50
|
-
not_an_address.errors
|
88
|
+
not_an_address.errors.full_messages
|
51
89
|
# => ['Address must have a street']
|
52
90
|
|
53
|
-
not_an_address.
|
54
|
-
# =>
|
55
|
-
```
|
56
|
-
|
57
|
-
In case you're wondering, the ```Model::InvalidModel``` is polymorphic with your
|
58
|
-
```Model``` in all the reader methods declared by ```attr_reader``` or ```attr_accessor```
|
91
|
+
not_an_address.errors.on(:street)
|
92
|
+
# => 'Address must have a street'
|
59
93
|
|
60
|
-
|
61
|
-
|
94
|
+
not_an_address.errors[:number]
|
95
|
+
# => []
|
62
96
|
|
63
|
-
|
97
|
+
not_an_address.errors.empty?
|
98
|
+
# => false
|
99
|
+
```
|
64
100
|
|
65
101
|
Thanks
|
66
102
|
------
|
data/hatch.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'hatch'
|
3
|
-
s.version = '0.0.
|
3
|
+
s.version = '0.0.7'
|
4
4
|
s.date = Time.now.strftime('%Y-%m-%d')
|
5
5
|
s.summary = 'Keep valid objects only'
|
6
6
|
s.description = "An address without a street? A person without a name? You don't need no invalid objects!"
|
data/lib/hatch.rb
CHANGED
@@ -58,7 +58,7 @@ module Hatch
|
|
58
58
|
|
59
59
|
def initialize(*validated_attributes)
|
60
60
|
@validated_attributes = validated_attributes
|
61
|
-
|
61
|
+
@errors = Errors.build(@validated_attributes)
|
62
62
|
respond_to_instance_methods
|
63
63
|
end
|
64
64
|
|
@@ -80,12 +80,6 @@ module Hatch
|
|
80
80
|
self.class.send :define_method, attribute.attr, -> {attribute.value}
|
81
81
|
end
|
82
82
|
end
|
83
|
-
|
84
|
-
def select_errors
|
85
|
-
@errors = @validated_attributes.select do |validated_attribute|
|
86
|
-
validated_attribute.invalid?
|
87
|
-
end.map(&:error)
|
88
|
-
end
|
89
83
|
end
|
90
84
|
|
91
85
|
private
|
@@ -151,5 +145,34 @@ module Hatch
|
|
151
145
|
new(error || "must be a positive number") {|value| !value.nil? && value > 0}
|
152
146
|
end
|
153
147
|
end
|
148
|
+
|
149
|
+
class Errors < Hash
|
150
|
+
def self.build(validated_attributes)
|
151
|
+
errors = new
|
152
|
+
validated_attributes.each do |validated_attribute|
|
153
|
+
if validated_attribute.invalid?
|
154
|
+
errors[validated_attribute.attr] = validated_attribute.error
|
155
|
+
else
|
156
|
+
errors[validated_attribute.attr] = []
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
errors
|
161
|
+
end
|
162
|
+
|
163
|
+
def on(attr)
|
164
|
+
self[attr]
|
165
|
+
end
|
166
|
+
|
167
|
+
def full_messages
|
168
|
+
messages = []
|
169
|
+
values.each {|value| messages << value unless value.empty?}
|
170
|
+
messages
|
171
|
+
end
|
172
|
+
|
173
|
+
def empty?
|
174
|
+
full_messages.empty?
|
175
|
+
end
|
176
|
+
end
|
154
177
|
end
|
155
178
|
|
@@ -13,13 +13,11 @@ end
|
|
13
13
|
class CommonValidationsTest < Test::Unit::TestCase
|
14
14
|
def test_presence
|
15
15
|
common_stuff = CommonStuff.hatch(present: nil, positive: 1)
|
16
|
-
|
17
|
-
assert common_stuff.errors.include?("must be present")
|
16
|
+
assert_equal 'must be present', common_stuff.errors.on(:present)
|
18
17
|
end
|
19
18
|
|
20
19
|
def test_positive_number
|
21
|
-
common_stuff = CommonStuff.hatch(present:
|
22
|
-
|
23
|
-
assert common_stuff.errors.include?("must be a positive number")
|
20
|
+
common_stuff = CommonStuff.hatch(present: 'here', positive: -1)
|
21
|
+
assert_equal 'must be a positive number', common_stuff.errors.on(:positive)
|
24
22
|
end
|
25
23
|
end
|
data/test/errors_test.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'support/helper'
|
2
|
+
require_relative 'support/address'
|
3
|
+
|
4
|
+
class ErrorsTest < Test::Unit::TestCase
|
5
|
+
def initialize(*args)
|
6
|
+
@address = Address.hatch(city: 'Buenos Aires', street: '', number: -1)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_errors_on
|
11
|
+
assert @address.errors.on(:city).empty?
|
12
|
+
assert_equal 'Address must have a street', @address.errors.on(:street)
|
13
|
+
assert_equal 'Address must have a positive number', @address.errors.on(:number)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_hash_accessor
|
17
|
+
assert @address.errors[:city].empty?
|
18
|
+
assert_equal 'Address must have a street', @address.errors[:street]
|
19
|
+
assert_equal 'Address must have a positive number', @address.errors[:number]
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_errors_full_messages
|
23
|
+
assert @address.errors.full_messages.include?('Address must have a street')
|
24
|
+
assert @address.errors.full_messages.include?('Address must have a positive number')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
data/test/validation_test.rb
CHANGED
@@ -1,33 +1,17 @@
|
|
1
1
|
require_relative 'support/helper'
|
2
2
|
require_relative 'support/address'
|
3
3
|
|
4
|
-
class
|
4
|
+
class ValidationTest < Test::Unit::TestCase
|
5
5
|
def test_valid
|
6
|
-
address = Address.hatch(street:
|
6
|
+
address = Address.hatch(street: 'Fake St', city: 'Buenos Aires', number: 1234)
|
7
7
|
assert address.is_a?(Address)
|
8
|
-
assert_equal address.instance_variable_get("@street"), "Fake St"
|
9
|
-
assert_equal address.instance_variable_get("@number"), 1234
|
10
|
-
assert_equal address.instance_variable_get("@city"), "Buenos Aires"
|
11
|
-
|
12
|
-
assert address.respond_to?(:errors)
|
13
|
-
assert address.errors.empty?
|
14
8
|
assert address.respond_to?(:valid?)
|
15
9
|
assert address.valid?
|
16
10
|
end
|
17
11
|
|
18
12
|
def test_invalid
|
19
|
-
address = Address.hatch(city:
|
20
|
-
assert address.is_a?(Address::InvalidAddress)
|
21
|
-
assert address.errors.include?("Address must have a street")
|
22
|
-
assert !address.errors.include?("Address must have a positive number")
|
23
|
-
assert !address.errors.include?("Address must have a city")
|
24
|
-
|
25
|
-
address = Address.hatch(street: "", number: -4)
|
13
|
+
address = Address.hatch(city: 'Buenos Aires', street: '', number: 1234)
|
26
14
|
assert address.is_a?(Address::InvalidAddress)
|
27
|
-
assert address.errors.include?("Address must have a street")
|
28
|
-
assert address.errors.include?("Address must have a positive number")
|
29
|
-
assert address.errors.include?("Address must have a city")
|
30
|
-
|
31
15
|
assert address.respond_to?(:valid?)
|
32
16
|
assert !address.valid?
|
33
17
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hatch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Tolchinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: An address without a street? A person without a name? You don't need
|
14
14
|
no invalid objects!
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- hatch.gemspec
|
23
23
|
- Rakefile
|
24
24
|
- test/common_validations_test.rb
|
25
|
+
- test/errors_test.rb
|
25
26
|
- test/polymorphism_test.rb
|
26
27
|
- test/validation_test.rb
|
27
28
|
- lib/hatch.rb
|