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 +7 -0
- data/CHANGELOG.markdown +2 -0
- data/LICENSE +21 -0
- data/README.markdown +75 -0
- data/lib/error_prone.rb +222 -0
- data/lib/error_prone/version.rb +3 -0
- metadata +49 -0
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
|
data/CHANGELOG.markdown
ADDED
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
|
data/lib/error_prone.rb
ADDED
@@ -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
|
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: []
|