error_prone 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c35c189bd7720a73b92c1e9f71286844cc81138
4
+ data.tar.gz: d12ddc14a3dade563cc49f8f3adb6530a22c3d30
5
+ SHA512:
6
+ metadata.gz: e1e02a55550ace75ae30e553ff764c10e2688ce5b0ea90b618c468b1055c955cab532550d0449c4fd17c9ea56bd361478c02cd699b7f10556627b16dad63ec9a
7
+ data.tar.gz: 9726de84a68b951b69ed47cdbf7ce8d37d5685a0548d0bfdca2bbb9b45645935813dbf9f4cec8dfe121fe3573f59bea84710d706b8d0ea41ad61cc16b85dd534
@@ -0,0 +1,2 @@
1
+ ### 0.1.0
2
+ * Created initial feature set.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Zee Spencer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,75 @@
1
+ ErrorProne is a dependency free library that puts control of when, how, and
2
+ where you validate your data in your capable hands.
3
+
4
+ ## Usage
5
+
6
+ ErrorProne has 3 primary modules:
7
+
8
+ * {ErrorProne::Model} - Object to validate
9
+ * {ErrorProne::Rule} - Specific rule to determine a field is valid
10
+ * {ErrorProne::Validator} - Object which collects and applies
11
+ {ErrorProne::Rule Rules} for a {ErrorProne::Model Model}
12
+
13
+ These are mixed in to your objects using the `include` method.
14
+
15
+ ### Example
16
+
17
+ ``` ruby
18
+ class Person < Struct.new(:name, :email)
19
+ include ErrorProne::Model
20
+ end
21
+
22
+ class ValidEmail
23
+ include ErrorProne::Rule
24
+ validates_as :is_email
25
+
26
+ def verify!
27
+ value.include?("@") # WORST. VALIDATION. EVER
28
+ end
29
+
30
+ def message
31
+ :invalid_email
32
+ end
33
+ end
34
+
35
+ include ErrorProne::Validator
36
+ validates :name, :present
37
+ validates :email, :is_email
38
+
39
+ good_person = Person.new("Zee", "zee@example.com")
40
+ validate!(good_person)
41
+ p good_person.errors_for(:name) # []
42
+ p good_person.errors_for(:email) # []
43
+ p good_person.valid? # true
44
+
45
+ bad_person = Person.new(nil, "foo")
46
+ validate!(bad_person)
47
+ p bad_person.valid? # false
48
+ p bad_person.errors_for(:name) # [:missing]
49
+ p bad_person.errors_for(:email) # [:invalid_email]
50
+ ```
51
+
52
+ ## Philosophy
53
+ ### Simple over Easy
54
+ ErrorProne isn't designed to minimize keystrokes. Instead, it exhibits a
55
+ pythonesque preference for expliciteness and minimal dependencies. This results
56
+ in a library that is powerful, portable, and comprehensible. ErrorProne eschews
57
+ metaprogramming in favor of a relatively boring codebase.
58
+
59
+ ### Supportive over Prescriptive
60
+ We rubyists sometimes prefer beauty of DSL regardless of how it prods users
61
+ towards highly coupled objects or locks them into an architecture that is more
62
+ about the library than the problem they're solving. ErrorProne supports your
63
+ design instead of prescribing it.
64
+
65
+ ## Contributing
66
+ OSS is all about the community. Feel free to submit new features, documentation
67
+ chagnes, and requests for help in the following ways:
68
+
69
+ 1. Submit a [pull request](pulls). Explain how your change meets the ErrorProne
70
+ [philosophy](#label-Philosophy). Include reasonable tests and rdoc.
71
+ 2. Open an [issue](issues). Explain how the proposed change meets the ErrorProne
72
+ [philosophy](#label-Philosophy).
73
+ 3. Ask a question on [Stack
74
+ Overflow](http://stackoverflow.com/questions/tagged/error-prone) and tweet
75
+ [@zspencer](http://twitter.com/zspencer) so I can answer it quickly
@@ -0,0 +1,222 @@
1
+ module ErrorProne
2
+
3
+
4
+ # Mixed in to objects you wish to validate.
5
+ #
6
+ # @example
7
+ #
8
+ # class FakeModel < Struct.new(:name)
9
+ # include ErrorProne::Model
10
+ # end
11
+ #
12
+ # model = FakeModel.new
13
+ # model.valid? # true
14
+ # model.add_error(:name, :too_cool)
15
+ # model.valid? # false
16
+ # model.errors_for(:name) # [:too_cool]
17
+
18
+ module Model
19
+
20
+ # @param [Symbol] field The field to find errors for
21
+ # @return [Array] the errors for the given field
22
+ def errors_for(field)
23
+ errors.for(field)
24
+ end
25
+
26
+ # @return [ErrorProne::Errors]
27
+ def errors
28
+ @errors ||= Errors.new
29
+ end
30
+
31
+ # @param [Symbol] field Identifies which field to add an error to
32
+ # @param [Symbol] error Identifies the type of error that occured
33
+ # @return [self] The model itself
34
+ def add_error(field, error)
35
+ errors.add(field, error)
36
+ self
37
+ end
38
+
39
+ # @return [Boolean] false if errors had been added. True if no errors.
40
+ def valid?
41
+ errors.empty?
42
+ end
43
+ end
44
+
45
+ # Mixed in to objects that can verify whether an {ErrorProne::Model} is valid
46
+ # or not.
47
+ #
48
+ # @example
49
+ # class FakeRule
50
+ #
51
+ # include ErrorProne::Rule
52
+ # validates_as :not_nil
53
+ #
54
+ # def verify!
55
+ # !value.nil?
56
+ # end
57
+ #
58
+ # def message
59
+ # :field_nil
60
+ # end
61
+ # end
62
+ #
63
+ module Rule
64
+ module ClassMethods
65
+
66
+ # @param [Symbol] rule_name Name to use when using validates on an {ErrorProne::Validator}
67
+ def validates_as(rule_name)
68
+ RuleSet.available_rules[rule_name] = self
69
+ end
70
+ end
71
+
72
+
73
+ attr_reader :object, :field, :value
74
+ # @param [Object] object Object to verify conforms to a rule
75
+ # @param [Symbol] field Field on the object that must conform to the rule
76
+ # @param [Hash] options often specific to the the Rule
77
+ def initialize(object, field, options = {})
78
+ @object = object
79
+ @field = field
80
+ @options = options
81
+ end
82
+
83
+ # Adds error to the object if verify! fails
84
+ # @return [Boolean]
85
+ def validate!
86
+ @value = object.send(field)
87
+ return true if verify!
88
+ object.add_error(field, message)
89
+ false
90
+ end
91
+
92
+ # Message to add when validate! finds an error. Must override in
93
+ # implementing classes.
94
+ # @return [Symbol]
95
+ def message
96
+ raise "You must set a message for rules to work"
97
+ end
98
+
99
+ # Verifies if the rule is followed. Must override in implementing classes.
100
+ # @return [Boolean]
101
+ def verify!
102
+ raise "You must provide a verify! method for rules to work. verify! should return a boolean"
103
+ end
104
+
105
+ def self.included(klazz)
106
+ klazz.extend(ClassMethods)
107
+ end
108
+ end
109
+
110
+ # Mixed in to objects you wish to use to validate other objects
111
+ #
112
+ # @example
113
+ # class ObjectToValidate < Struct.new(:name)
114
+ # include ErrorProne::Model
115
+ # end
116
+ #
117
+ # class ObjectValidator
118
+ # include ErrorProne::Validator
119
+ # validates :name, :present
120
+ # end
121
+ #
122
+ # object = ObjectToValidate.new(nil)
123
+ # ObjectValidator.new.validate!(object) # false
124
+ # object.valid? # false
125
+ # object.errors_for(:name) # [:missing]
126
+
127
+ module Validator
128
+
129
+ module ClassMethods
130
+ # Contains rules the validator will run when .validate! is called
131
+ #
132
+ # @return (ErrorProne::RuleSet)
133
+ def rules
134
+ @rules ||= RuleSet.new
135
+ end
136
+
137
+
138
+ # Adds a rule the validator runs when .validate! is called.
139
+ #
140
+ # @param (Symbol) field Method to call on the object to validate
141
+ # @param (Symbol) rule Name of rule to apply, defined by {ErrorProne::Rule}.validates_as
142
+ # @param (Hash) options to pass to the {ErrorProne::Rule} when instantiating
143
+ def validates(field, rule, options={})
144
+ rules.add(field, rule, options)
145
+ end
146
+
147
+ # Validates all rules against the given object
148
+ #
149
+ # @param (Object) object Object to validate each rule against
150
+ # @return (Boolean) True if all rules are valid, false otherwise.
151
+ def validate!(object)
152
+ rules.all_valid_for? object
153
+ end
154
+ end
155
+
156
+ # Alias for {ErrorProne::Validator}.validate
157
+ def validate!(object)
158
+ self.class.validate!(object)
159
+ end
160
+
161
+ def self.included(base)
162
+ base.extend(ClassMethods)
163
+ end
164
+
165
+ end
166
+
167
+ class RuleSet < Hash
168
+ def self.available_rules
169
+ @available_rules ||= {}
170
+ end
171
+
172
+ def available_rules
173
+ self.class.available_rules
174
+ end
175
+
176
+ def for(field)
177
+ self[field] ||= []
178
+ end
179
+
180
+ def add(field, rule_name, options = {})
181
+ raise "rule #{rule_name} is not available" unless available_rules.has_key?(rule_name)
182
+ self.for(field).push(rule: available_rules[rule_name], options: options)
183
+ self
184
+ end
185
+
186
+
187
+ def all_valid_for?(object)
188
+ all? do |field, rules|
189
+ rules.all? do |rule_config|
190
+ rule = rule_config[:rule].new(object, field, rule_config[:options])
191
+ rule.validate!
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ class PresenceRule
198
+ include Rule
199
+ validates_as :present
200
+
201
+ def verify!
202
+ [:nil?, :empty?].select { |method| value.respond_to?(method) }.none? { |method|
203
+ value.send(method)
204
+ }
205
+ end
206
+
207
+ def message
208
+ :missing
209
+ end
210
+ end
211
+
212
+ class Errors < Hash
213
+ def add(field, error)
214
+ self.for(field).push(error)
215
+ self
216
+ end
217
+
218
+ def for(field)
219
+ self[field] ||= []
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,3 @@
1
+ module ErrorProne
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: error_prone
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Zee Spencer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ErrorProne lets you choose where, when, and how to validate data without
14
+ tying you to ORMs or application frameworks.
15
+ email:
16
+ - zee@zeespencer.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/error_prone/version.rb
22
+ - lib/error_prone.rb
23
+ - LICENSE
24
+ - README.markdown
25
+ - CHANGELOG.markdown
26
+ homepage: http://github.com/zspencer/error_prone
27
+ licenses: []
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.0.3
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: The no-frills, dependency-free data validation library
49
+ test_files: []