hatch 0.1.2 → 0.1.3
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 +6 -14
- data/README.md +29 -2
- data/hatch.gemspec +1 -1
- data/lib/hatch.rb +58 -36
- data/test/namespace_test.rb +12 -0
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
NGM4MjIyZmI2MzE3OTgzNmQ5YzI5YjI3OTkwN2I3NDRiNGQ1M2JiNTQzMzgw
|
10
|
-
NzAyYTc1ZmM0OTRiZTg3Y2RmMTNhYzA2OWU2NDBlYjE1MmRiYTMwZGFjYTY5
|
11
|
-
ODA2ZTk2YzA2ZDU2NDI4MDM4MzZhZTIyYTEwNDVmNjg5ZjBmZmU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
Y2QyZDkyNjA2Y2Y5YzM5ZjkzNzdiOGU0MDYzNzlkNTJhMTY0NTA3MjE4YjIz
|
14
|
-
Yjc1NTdhYjBiZWMyYjJjYzRkN2I2ZmE0MWU5NjBiOWNjNDdiODBjMWRlOTc3
|
15
|
-
NmJkYzcwYTViZmVjMDFhYmU5YWE2YjFlODRiMzY4YjJmMTczZGY=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bd01fbcc30072e37286dc7730b09873dbf7a51df
|
4
|
+
data.tar.gz: c69e71d77e49ee54a0f669dd520e339a2dba26b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43cbf31600f855994c6f323e2b2c6c69b78742d7497748ef92e59c53bb5e794e103437ff4df1007c3530cd1f3ac657e52ce141d866a60f1d8279cb4d9a36cab7
|
7
|
+
data.tar.gz: e05048b602d6a90c3736d0096f8cb141960b65b504da6c6506c382a30866d3de4b19a83231ebcd53b99963bd59cf6590e9312b24aa61366e540656095e154dee
|
data/README.md
CHANGED
@@ -11,7 +11,6 @@ Installation
|
|
11
11
|
Usage
|
12
12
|
-----
|
13
13
|
|
14
|
-
|
15
14
|
Tell `Hatch` how to certify the attributes of your models, and it will give you the appropriate object.
|
16
15
|
|
17
16
|
If you don't hatch your model with all the correct attributes, you'll get an object representing an invalid instance of it.
|
@@ -55,7 +54,7 @@ In case you're wondering, the `Model::InvalidModel` is polymorphic with your `Mo
|
|
55
54
|
class Address
|
56
55
|
include Hatch
|
57
56
|
|
58
|
-
certifies(:street, :not_empty,
|
57
|
+
certifies(:street, :not_empty, "This is an error! Where's my street?!")
|
59
58
|
certifies(:number, :positive_number)
|
60
59
|
end
|
61
60
|
```
|
@@ -91,6 +90,34 @@ not_an_address.errors.empty?
|
|
91
90
|
# => false
|
92
91
|
```
|
93
92
|
|
93
|
+
Interesting use cases
|
94
|
+
---------------------
|
95
|
+
|
96
|
+
`Hatch` is essentially a validator, so you can rely on it to certify your attributes before they get to the model.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class AddressForm
|
100
|
+
include Hatch
|
101
|
+
|
102
|
+
certify(:street, 'Address must have a street') do |street|
|
103
|
+
!street.nil? && !street.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
certify(:number, 'Address must have a positive number') do |number|
|
107
|
+
!number.nil? && number > 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Meanwhile, in your favorite Ruby web framework...
|
112
|
+
address_form = AddressForm.hatch(params['address'])
|
113
|
+
|
114
|
+
if address_form.valid?
|
115
|
+
Address.create(params['address'])
|
116
|
+
else
|
117
|
+
# try again
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
94
121
|
One of the nicest things about `Hatch` is that errors can be any object of your desire! Power to thy user.
|
95
122
|
|
96
123
|
```ruby
|
data/hatch.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'hatch'
|
3
|
-
s.version = '0.1.
|
3
|
+
s.version = '0.1.3'
|
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
@@ -22,7 +22,7 @@ module Hatch
|
|
22
22
|
include InvalidInstanceMethods
|
23
23
|
end
|
24
24
|
|
25
|
-
klass.const_set("Invalid#{klass}", invalid_class)
|
25
|
+
klass.const_set("Invalid#{klass.name.split('::').last}", invalid_class)
|
26
26
|
end
|
27
27
|
|
28
28
|
def certify(attribute, error, &block)
|
@@ -45,77 +45,101 @@ module Hatch
|
|
45
45
|
build(validated_attributes)
|
46
46
|
end
|
47
47
|
|
48
|
+
def build(validated_attributes)
|
49
|
+
if validated_attributes.all? {|validated_attribute| validated_attribute.valid?}
|
50
|
+
set_instance_variables(new, *validated_attributes)
|
51
|
+
else
|
52
|
+
const_get("Invalid#{self.to_s.split('::').last}").new(*validated_attributes)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
private :build
|
56
|
+
|
57
|
+
def set_instance_variables(instance, *args)
|
58
|
+
@@validations[instance.class.name.to_sym].keys.each_with_index do |attribute, index|
|
59
|
+
instance.instance_variable_set("@#{attribute}", args[index].value)
|
60
|
+
end
|
61
|
+
instance
|
62
|
+
end
|
63
|
+
private :set_instance_variables
|
64
|
+
|
48
65
|
module InvalidInstanceMethods
|
49
|
-
|
66
|
+
attr :errors
|
50
67
|
|
51
68
|
def initialize(*validated_attributes)
|
52
69
|
@validated_attributes = validated_attributes
|
53
70
|
@errors = Errors.build(@validated_attributes)
|
54
|
-
|
71
|
+
respond_to_readable_attributes
|
55
72
|
end
|
56
73
|
|
57
74
|
def valid?
|
58
75
|
false
|
59
76
|
end
|
60
77
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
78
|
+
def respond_to_readable_attributes
|
79
|
+
readable_attributes.each do |readable_attribute|
|
80
|
+
self.class.send(:define_method,
|
81
|
+
readable_attribute.attribute,
|
82
|
+
-> {readable_attribute.value})
|
66
83
|
end
|
67
84
|
end
|
85
|
+
private :respond_to_readable_attributes
|
68
86
|
|
69
|
-
def
|
70
|
-
|
71
|
-
instance_methods = extended_klass.instance_methods(false)
|
87
|
+
def readable_attributes
|
88
|
+
instance_methods = extended_class.instance_methods(false)
|
72
89
|
|
73
90
|
@validated_attributes.select do |validated_attribute|
|
74
|
-
instance_methods.include?(validated_attribute.
|
91
|
+
instance_methods.include?(validated_attribute.attribute)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
private :readable_attributes
|
95
|
+
|
96
|
+
def extended_class
|
97
|
+
self.class.name.gsub(/(.*)(\:\:Invalid)(.*)/, '\1').split('::').inject(Object) do |mod, class_name|
|
98
|
+
mod.const_get(class_name)
|
75
99
|
end
|
76
100
|
end
|
101
|
+
private :extended_class
|
77
102
|
end
|
103
|
+
end
|
78
104
|
|
79
|
-
|
105
|
+
class ValidatedAttribute
|
106
|
+
attr :attribute, :value, :error
|
80
107
|
|
81
|
-
def
|
82
|
-
if
|
83
|
-
|
108
|
+
def self.validate(attribute, value, error, &block)
|
109
|
+
if yield(value)
|
110
|
+
ValidAttribute.new(attribute, value)
|
84
111
|
else
|
85
|
-
|
112
|
+
InvalidAttribute.new(attribute, value, error)
|
86
113
|
end
|
87
114
|
end
|
88
115
|
|
89
|
-
def
|
90
|
-
|
91
|
-
instance.instance_variable_set("@#{attribute}", args[index].value)
|
92
|
-
end
|
93
|
-
instance
|
116
|
+
def initialize(attribute, value, error = [])
|
117
|
+
@attribute, @value, @error = attribute, value, error
|
94
118
|
end
|
95
119
|
end
|
96
120
|
|
97
|
-
class ValidatedAttribute
|
98
|
-
|
99
|
-
|
100
|
-
def self.validate(attr, value, error, &block)
|
101
|
-
new(attr, value, error, yield(value))
|
121
|
+
class ValidAttribute < ValidatedAttribute
|
122
|
+
def valid?
|
123
|
+
true
|
102
124
|
end
|
103
125
|
|
104
|
-
def
|
105
|
-
|
126
|
+
def invalid?
|
127
|
+
false
|
106
128
|
end
|
129
|
+
end
|
107
130
|
|
131
|
+
class InvalidAttribute < ValidatedAttribute
|
108
132
|
def valid?
|
109
|
-
|
133
|
+
false
|
110
134
|
end
|
111
135
|
|
112
136
|
def invalid?
|
113
|
-
|
137
|
+
true
|
114
138
|
end
|
115
139
|
end
|
116
140
|
|
117
141
|
class Validation
|
118
|
-
|
142
|
+
attr :error, :block
|
119
143
|
|
120
144
|
def initialize(error, &block)
|
121
145
|
@error, @block = error, block
|
@@ -151,14 +175,12 @@ module Hatch
|
|
151
175
|
full_messages.empty?
|
152
176
|
end
|
153
177
|
|
154
|
-
private
|
155
|
-
|
156
178
|
def self.attributes_and_errors(validated_attributes)
|
157
179
|
validated_attributes.map do |validated_attribute|
|
158
|
-
[validated_attribute.
|
159
|
-
validated_attribute.invalid? ? validated_attribute.error : [] ]
|
180
|
+
[validated_attribute.attribute, validated_attribute.error]
|
160
181
|
end
|
161
182
|
end
|
183
|
+
private_class_method :attributes_and_errors
|
162
184
|
end
|
163
185
|
end
|
164
186
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative 'support/namespaced_address'
|
3
|
+
|
4
|
+
class NamespaceTest < MiniTest::Unit::TestCase
|
5
|
+
def test_namespace
|
6
|
+
address = SomeApp::Address.hatch(street: 'Fake St', number: 1234, city: 'Buenos Aires')
|
7
|
+
assert_instance_of SomeApp::Address, address
|
8
|
+
|
9
|
+
address = SomeApp::Address.hatch(street: 'Fake St', number: -1, city: 'Buenos Aires')
|
10
|
+
assert_instance_of SomeApp::Address::InvalidAddress, address
|
11
|
+
end
|
12
|
+
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.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Tolchinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-03-19 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!
|
@@ -19,13 +19,14 @@ extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
21
|
- README.md
|
22
|
-
- hatch.gemspec
|
23
22
|
- Rakefile
|
23
|
+
- hatch.gemspec
|
24
|
+
- lib/hatch.rb
|
24
25
|
- test/common_validations_test.rb
|
25
26
|
- test/errors_test.rb
|
27
|
+
- test/namespace_test.rb
|
26
28
|
- test/polymorphism_test.rb
|
27
29
|
- test/validation_test.rb
|
28
|
-
- lib/hatch.rb
|
29
30
|
homepage: http://github.com/tonchis/hatch
|
30
31
|
licenses:
|
31
32
|
- MIT
|
@@ -36,17 +37,17 @@ require_paths:
|
|
36
37
|
- lib
|
37
38
|
required_ruby_version: !ruby/object:Gem::Requirement
|
38
39
|
requirements:
|
39
|
-
- -
|
40
|
+
- - ">="
|
40
41
|
- !ruby/object:Gem::Version
|
41
42
|
version: '0'
|
42
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
44
|
requirements:
|
44
|
-
- -
|
45
|
+
- - ">="
|
45
46
|
- !ruby/object:Gem::Version
|
46
47
|
version: '0'
|
47
48
|
requirements: []
|
48
49
|
rubyforge_project:
|
49
|
-
rubygems_version: 2.
|
50
|
+
rubygems_version: 2.2.0
|
50
51
|
signing_key:
|
51
52
|
specification_version: 4
|
52
53
|
summary: Keep valid objects only
|