hatch 0.0.6 → 0.0.7

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NWM5Y2NiNzZiYjYzYWQ5MWVhOWJkMjYyYTZjMWYyOThkY2JkNzg4Yg==
4
+ MzJjNWMxMjRlMzM0OGM0YTk2YWY3MmQ5YjAyZWNiMDZjYjg1YWQ0OA==
5
5
  data.tar.gz: !binary |-
6
- YmVkMjEwZjRhZTEwMDY1MmRjMzNjZWUxZmJiYTdlOWZlMTgzNjFhMA==
6
+ NzJhNTQyYjJhMTUyOWZmOWE1OTdjMzY2ZDZmMDQ0MmViY2Y5ODEzZA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZDYxZTI3ODQ5MzZmNjBhNTczNjdkMzgwZWY4MGU0ZThkNzdmNzFmMDc1MmRm
10
- NzNjNWEwYTU3YjZhNGY5ZjM0OGE1NDU4NjlmNzRmOTIyZTE4NWY4Mjc5ZTI1
11
- Y2U3NDk5OTJlM2ZjYjQ3MjkzMzFjZmIxOWRmYzc2MTk3MTE5M2Q=
9
+ MTY4NzUzN2Y3OGYyMWFlYmVmNGVjMTI1NDg5Yjc0Y2JiOGY2YmM4NWQyY2Fm
10
+ OTFlMTc0Y2Q5ZWE0YmFhODJkNTc4YWY3YjNhMmQ1MDU3ZWQyNzI1ZmIxZmFk
11
+ ZjA4ZDNlODYwMmY0NTgzMmQyYTY1YTFiMzQwNDc3YzBkMTVlYzY=
12
12
  data.tar.gz: !binary |-
13
- MTI3ZjFmNWQwY2Q3MmU3ZDAwMjM4ZDNlMDZjNGIxZmQxZTRhZDMzYTY0N2Zm
14
- N2FmNzM4ZjVmZjY1NmI1ZjI3OTM2MDI2NTY2MjU0ZDhhNTgwYWZjYzY3N2Uz
15
- NTllYjk0OTBkYzhmMmYxZjA0MTE1OTRmZTQ2ZjI1OTM4MDNmOGQ=
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 ```Hatch``` how to certify the attributes of your models, and he will give you
8
- the appropiate object.
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 ```Hatch``` with the ```attributes``` message and
39
- then use ```certify(:attribute, 'error message', &validation)``` to verify when an
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
- You'll also get some handy ```errors``` and ```valid?``` methods for both your valid
43
- and invalid model instances.
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.valid?
54
- # => false
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
- Installation
61
- ------------
94
+ not_an_address.errors[:number]
95
+ # => []
62
96
 
63
- $ gem install hatch
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.6'
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
- select_errors
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
- assert common_stuff.is_a?(CommonStuff::InvalidCommonStuff)
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: "here", positive: -1)
22
- assert common_stuff.is_a?(CommonStuff::InvalidCommonStuff)
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
@@ -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
+
@@ -1,33 +1,17 @@
1
1
  require_relative 'support/helper'
2
2
  require_relative 'support/address'
3
3
 
4
- class ValidTest < Test::Unit::TestCase
4
+ class ValidationTest < Test::Unit::TestCase
5
5
  def test_valid
6
- address = Address.hatch(street: "Fake St", city: "Buenos Aires", number: 1234)
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: "Buenos Aires", street: "", number: 1234)
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.6
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-21 00:00:00.000000000 Z
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