hatch 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MDlkZmRlM2ViZDQxZDFiODVlNGY3ZTNmNzcyMTMzZTViZWQ5OTc1Mw==
5
- data.tar.gz: !binary |-
6
- YTk3Nzg0NDk0MGIzMzI4NWNmNzIzZjdkZWM3YjM3YjhkMGEyODA1ZQ==
7
- !binary "U0hBNTEy":
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, 'This is an error! Where's my street?!')
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'hatch'
3
- s.version = '0.1.2'
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!"
@@ -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
- attr_reader :errors
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
- respond_to_instance_methods
71
+ respond_to_readable_attributes
55
72
  end
56
73
 
57
74
  def valid?
58
75
  false
59
76
  end
60
77
 
61
- private
62
-
63
- def respond_to_instance_methods
64
- attributes_with_reader_method.each do |attribute|
65
- self.class.send :define_method, attribute.attr, -> {attribute.value}
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 attributes_with_reader_method
70
- extended_klass = Kernel.const_get(self.class.to_s.split("Invalid").last)
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.attr)
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
- private
105
+ class ValidatedAttribute
106
+ attr :attribute, :value, :error
80
107
 
81
- def build(validated_attributes)
82
- if validated_attributes.all? {|validated_attribute| validated_attribute.valid?}
83
- set_instance_variables(new, *validated_attributes)
108
+ def self.validate(attribute, value, error, &block)
109
+ if yield(value)
110
+ ValidAttribute.new(attribute, value)
84
111
  else
85
- const_get("Invalid#{self}").new(*validated_attributes)
112
+ InvalidAttribute.new(attribute, value, error)
86
113
  end
87
114
  end
88
115
 
89
- def set_instance_variables(instance, *args)
90
- @@validations[instance.class.to_s.to_sym].keys.each_with_index do |attribute, index|
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
- attr_reader :attr, :value, :error
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 initialize(attr, value, error, valid)
105
- @attr, @value, @error, @valid = attr, value, error, valid
126
+ def invalid?
127
+ false
106
128
  end
129
+ end
107
130
 
131
+ class InvalidAttribute < ValidatedAttribute
108
132
  def valid?
109
- @valid
133
+ false
110
134
  end
111
135
 
112
136
  def invalid?
113
- !@valid
137
+ true
114
138
  end
115
139
  end
116
140
 
117
141
  class Validation
118
- attr_reader :error, :block
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.attr,
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.2
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: 2013-08-07 00:00:00.000000000 Z
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.0.0
50
+ rubygems_version: 2.2.0
50
51
  signing_key:
51
52
  specification_version: 4
52
53
  summary: Keep valid objects only