validus 0.0.1
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/README.md +88 -0
- data/Rakefile +56 -0
- data/lib/validus.rb +62 -0
- data/lib/validus/errors.rb +35 -0
- data/lib/validus/version.rb +3 -0
- data/test/test_helper.rb +4 -0
- data/test/validus/errors_test.rb +50 -0
- data/test/validus_test.rb +84 -0
- data/validus.gemspec +26 -0
- metadata +132 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Validus
|
2
|
+
|
3
|
+
Add validation support to Plain Old Ruby Objects.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'validus'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install validus
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Include this module in a target class and override the `validate` method. Use
|
22
|
+
`valid?` to perform the validation.
|
23
|
+
|
24
|
+
Example:
|
25
|
+
|
26
|
+
require "validus"
|
27
|
+
|
28
|
+
class Person
|
29
|
+
include Validus
|
30
|
+
|
31
|
+
attr_accessor :name, :age
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@name = ''
|
35
|
+
@age = 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate
|
39
|
+
errors.add(:name, 'cannot be blank') if name == ''
|
40
|
+
errors.add(:age, 'must be greater than 0') if age <= 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
person = Person.new
|
45
|
+
person.valid? # => false
|
46
|
+
person.errors.for(:name).to_a # => ['cannot be blank']
|
47
|
+
person.errors.full_messages.to_a # => ['name cannot be blank', 'age must be greater than 0']
|
48
|
+
|
49
|
+
person.name = 'John'
|
50
|
+
person.age = 20
|
51
|
+
|
52
|
+
person.valid? # => true
|
53
|
+
person.errors.empty? # => true
|
54
|
+
|
55
|
+
See [documentation](http://www.rubydoc.info/github/bnadlerjr/validus/frames) for more details.
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create new Pull Request
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
Copyright (c) 2012 Bob Nadler
|
68
|
+
|
69
|
+
MIT License
|
70
|
+
|
71
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
72
|
+
a copy of this software and associated documentation files (the
|
73
|
+
"Software"), to deal in the Software without restriction, including
|
74
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
75
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
76
|
+
permit persons to whom the Software is furnished to do so, subject to
|
77
|
+
the following conditions:
|
78
|
+
|
79
|
+
The above copyright notice and this permission notice shall be
|
80
|
+
included in all copies or substantial portions of the Software.
|
81
|
+
|
82
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
83
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
84
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
85
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
86
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
87
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
88
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rake/testtask"
|
4
|
+
require "rdoc/task"
|
5
|
+
require "flay_task"
|
6
|
+
require "flog"
|
7
|
+
|
8
|
+
DEFAULT_TASKS = %w[test flog flay]
|
9
|
+
MAIN_RDOC = 'README.md'
|
10
|
+
EXTRA_RDOC_FILES = [MAIN_RDOC]
|
11
|
+
LIB_FILES = Dir["lib/**/*.rb"]
|
12
|
+
TEST_FILES = Dir["test/**/*_test.rb"]
|
13
|
+
TITLE = 'Validus'
|
14
|
+
|
15
|
+
# Import external rake tasks
|
16
|
+
Dir.glob('tasks/*.rake').each { |r| import r }
|
17
|
+
|
18
|
+
desc "Default tasks: #{DEFAULT_TASKS.join(', ')}"
|
19
|
+
task :default => DEFAULT_TASKS
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.libs << 'test'
|
23
|
+
t.test_files = TEST_FILES
|
24
|
+
end
|
25
|
+
|
26
|
+
RDoc::Task.new do |t|
|
27
|
+
t.main = MAIN_RDOC
|
28
|
+
t.rdoc_dir = 'doc'
|
29
|
+
t.rdoc_files.include(EXTRA_RDOC_FILES, LIB_FILES)
|
30
|
+
t.options << '-q'
|
31
|
+
t.title = TITLE
|
32
|
+
end
|
33
|
+
|
34
|
+
FlayTask.new do |t|
|
35
|
+
t.dirs = %w[lib]
|
36
|
+
end
|
37
|
+
|
38
|
+
task :flog do
|
39
|
+
flog = Flog.new
|
40
|
+
flog.flog ['lib']
|
41
|
+
threshold = 50
|
42
|
+
|
43
|
+
bad_methods = flog.totals.select do |name, score|
|
44
|
+
score > threshold
|
45
|
+
end
|
46
|
+
|
47
|
+
bad_methods.sort do |a, b|
|
48
|
+
a[1] <=> b[1]
|
49
|
+
end.each do |name, score|
|
50
|
+
puts "%8.1f: %s" % [score, name]
|
51
|
+
end
|
52
|
+
|
53
|
+
unless bad_methods.empty?
|
54
|
+
raise "#{bad_methods.size} methods have a flog complexity > #{threshold}"
|
55
|
+
end
|
56
|
+
end
|
data/lib/validus.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "validus/version"
|
2
|
+
require "validus/errors"
|
3
|
+
|
4
|
+
# Add validation support to Plain Old Ruby Objects. Include this module in a
|
5
|
+
# target class and override the +validate+ method. Use +#valid?+ to perform
|
6
|
+
# the validation.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# require "validus"
|
11
|
+
#
|
12
|
+
# class Person
|
13
|
+
# include Validus
|
14
|
+
#
|
15
|
+
# attr_accessor :name, :age
|
16
|
+
#
|
17
|
+
# def initialize
|
18
|
+
# @name = ''
|
19
|
+
# @age = 0
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def validate
|
23
|
+
# errors.add(:name, 'cannot be blank') if name == ''
|
24
|
+
# errors.add(:age, 'must be greater than 0') if age <= 0
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# person = Person.new
|
29
|
+
# person.valid? # => false
|
30
|
+
# person.errors.for(:name).to_a # => ['cannot be blank']
|
31
|
+
# person.errors.full_messages.to_a # => ['name cannot be blank', 'age must be greater than 0']
|
32
|
+
#
|
33
|
+
# person.name = 'John'
|
34
|
+
# person.age = 20
|
35
|
+
#
|
36
|
+
# person.valid? # => true
|
37
|
+
# person.errors.empty? # => true
|
38
|
+
module Validus
|
39
|
+
# Abstract method that performs validation. Override this method in the
|
40
|
+
# target class. Overriding methods should use +errors#add+ to add
|
41
|
+
# validation errors. For example:
|
42
|
+
#
|
43
|
+
# def validate
|
44
|
+
# errors.add(:name, 'cannot be blank') if name.blank?
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# This method is not meant to be called directly... use +#valid?+ instead.
|
48
|
+
def validate
|
49
|
+
end
|
50
|
+
|
51
|
+
# Calls +validate+ and returns +true+ if there are any +errors+ on the target's attributes.
|
52
|
+
def valid?
|
53
|
+
errors.clear
|
54
|
+
validate
|
55
|
+
errors.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
# An instance of an +Errors+ object.
|
59
|
+
def errors
|
60
|
+
@errors ||= Errors.new
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Validus
|
2
|
+
# Represents a collection of errors.
|
3
|
+
class Errors
|
4
|
+
def initialize
|
5
|
+
@errors = Hash.new { |hash, key| hash[key] = [] }
|
6
|
+
end
|
7
|
+
|
8
|
+
# Add an error +message+ for an +attribute+.
|
9
|
+
def add(attribute, message)
|
10
|
+
@errors[attribute] << message
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
@errors.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
@errors.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an Enumerator consisting of all errors associated
|
22
|
+
# with +attribute+.
|
23
|
+
def for(attribute)
|
24
|
+
@errors[attribute].to_enum
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns an Enumerator consisting of all errors for all attributes. The
|
28
|
+
# name of the attribute is pre-pended to the error message.
|
29
|
+
def full_messages
|
30
|
+
@errors.map do |k, v|
|
31
|
+
v.map { |error| "#{k} #{error}"}
|
32
|
+
end.flatten.to_enum
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
require_relative "../../lib/validus/errors"
|
3
|
+
|
4
|
+
module Validus
|
5
|
+
class ErrorsTest < Test::Unit::TestCase
|
6
|
+
setup do
|
7
|
+
@errors = Errors.new
|
8
|
+
end
|
9
|
+
|
10
|
+
test "add an error" do
|
11
|
+
@errors.add(:name, "cannot be empty")
|
12
|
+
refute(@errors.empty?, "did not expect errors to be empty")
|
13
|
+
end
|
14
|
+
|
15
|
+
test "can clear errors" do
|
16
|
+
@errors.add(:name, "cannot be empty")
|
17
|
+
refute(@errors.empty?, "did not expect errors to be empty")
|
18
|
+
|
19
|
+
@errors.clear
|
20
|
+
assert(@errors.empty?, "expected errors to be empty")
|
21
|
+
end
|
22
|
+
|
23
|
+
test "can get errors for a particular attribute" do
|
24
|
+
@errors.add(:name, "cannot be empty")
|
25
|
+
assert_equal(['cannot be empty'], @errors.for(:name).to_a)
|
26
|
+
end
|
27
|
+
|
28
|
+
test "add multiple errors for a single attribute" do
|
29
|
+
@errors.add(:name, "cannot be empty")
|
30
|
+
@errors.add(:name, "must be 10 characters")
|
31
|
+
|
32
|
+
expected = ['cannot be empty', 'must be 10 characters']
|
33
|
+
assert_equal(expected, @errors.for(:name).to_a)
|
34
|
+
end
|
35
|
+
|
36
|
+
test "can get full error messages" do
|
37
|
+
@errors.add(:name, "cannot be empty")
|
38
|
+
@errors.add(:name, "must be 10 characters")
|
39
|
+
@errors.add(:age, "must be greater than zero")
|
40
|
+
|
41
|
+
expected = [
|
42
|
+
'name cannot be empty',
|
43
|
+
'name must be 10 characters',
|
44
|
+
'age must be greater than zero'
|
45
|
+
]
|
46
|
+
|
47
|
+
assert_equal(expected, @errors.full_messages.to_a)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
require_relative "../lib/validus"
|
3
|
+
|
4
|
+
class ValidusTest < Test::Unit::TestCase
|
5
|
+
BlankTarget = Class.new do
|
6
|
+
include Validus
|
7
|
+
end
|
8
|
+
|
9
|
+
TargetWithAutoError = Class.new do
|
10
|
+
include Validus
|
11
|
+
|
12
|
+
def validate
|
13
|
+
errors.add(:name, 'cannot be empty')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
test "valid? returns true if there are no errors" do
|
18
|
+
assert(BlankTarget.new.valid?, "expected valid? to be true")
|
19
|
+
end
|
20
|
+
|
21
|
+
test "#errors is empty if target is valid" do
|
22
|
+
assert(BlankTarget.new.errors.empty?, "expected errors to be empty")
|
23
|
+
end
|
24
|
+
|
25
|
+
test "valid? returns false if there are any errors" do
|
26
|
+
refute(TargetWithAutoError.new.valid?, "expected valid? to be false")
|
27
|
+
end
|
28
|
+
|
29
|
+
test "valid? clears out any existing errors before validating" do
|
30
|
+
Target = Class.new do
|
31
|
+
include Validus
|
32
|
+
|
33
|
+
attr_accessor :name
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@name = ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate
|
40
|
+
errors.add(:name, 'cannot be blank') if name == ''
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
target = Target.new
|
45
|
+
refute(target.valid?, "expected target to be invalid")
|
46
|
+
|
47
|
+
target.name = 'John'
|
48
|
+
assert(target.valid?, "expected target to be valid")
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
test "end to end" do
|
53
|
+
Person = Class.new do
|
54
|
+
include Validus
|
55
|
+
|
56
|
+
attr_accessor :name, :age
|
57
|
+
|
58
|
+
def initialize
|
59
|
+
@name = ''
|
60
|
+
@age = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def validate
|
64
|
+
errors.add(:name, 'cannot be blank') if name == ''
|
65
|
+
errors.add(:age, 'must be greater than 0') if age <= 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
person = Person.new
|
70
|
+
|
71
|
+
refute(person.valid?, "expected person to be invalid")
|
72
|
+
assert_equal(['cannot be blank'], person.errors.for(:name).to_a)
|
73
|
+
assert_equal(
|
74
|
+
['name cannot be blank', 'age must be greater than 0'],
|
75
|
+
person.errors.full_messages.to_a
|
76
|
+
)
|
77
|
+
|
78
|
+
person.name = 'John'
|
79
|
+
person.age = 20
|
80
|
+
|
81
|
+
assert(person.valid?, "expected person to be valid")
|
82
|
+
assert(person.errors.empty?, "expected errors to be empty")
|
83
|
+
end
|
84
|
+
end
|
data/validus.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/validus/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Bob Nadler, Jr."]
|
6
|
+
gem.email = ["bnadlerjr@gmail.com"]
|
7
|
+
gem.description = %q{Valdations for Plain Old Ruby Objects.}
|
8
|
+
gem.summary = %q{Valdations for Plain Old Ruby Objects.}
|
9
|
+
gem.homepage = "https://github.com/bnadlerjr/validus"
|
10
|
+
gem.has_rdoc = true
|
11
|
+
gem.license = 'MIT'
|
12
|
+
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
gem.name = "validus"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = Validus::VERSION
|
19
|
+
|
20
|
+
gem.add_development_dependency "contest", "~> 0.1.3"
|
21
|
+
gem.add_development_dependency "flay", "~> 1.4.3"
|
22
|
+
gem.add_development_dependency "flog", "~> 2.5.3"
|
23
|
+
gem.add_development_dependency "minitest-reporters", "~> 0.9.0"
|
24
|
+
gem.add_development_dependency "rake", "~> 0.9.2.2"
|
25
|
+
gem.add_development_dependency "rdoc", "~> 3.12"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bob Nadler, Jr.
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: contest
|
16
|
+
requirement: &70301779203040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.3
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70301779203040
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: flay
|
27
|
+
requirement: &70301779202220 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.4.3
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70301779202220
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: flog
|
38
|
+
requirement: &70301779201560 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.5.3
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70301779201560
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: minitest-reporters
|
49
|
+
requirement: &70301779200600 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70301779200600
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rake
|
60
|
+
requirement: &70301779216480 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.9.2.2
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70301779216480
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rdoc
|
71
|
+
requirement: &70301779215980 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.12'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70301779215980
|
80
|
+
description: Valdations for Plain Old Ruby Objects.
|
81
|
+
email:
|
82
|
+
- bnadlerjr@gmail.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- lib/validus.rb
|
92
|
+
- lib/validus/errors.rb
|
93
|
+
- lib/validus/version.rb
|
94
|
+
- test/test_helper.rb
|
95
|
+
- test/validus/errors_test.rb
|
96
|
+
- test/validus_test.rb
|
97
|
+
- validus.gemspec
|
98
|
+
homepage: https://github.com/bnadlerjr/validus
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
hash: 1860856656352002206
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
hash: 1860856656352002206
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.10
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Valdations for Plain Old Ruby Objects.
|
129
|
+
test_files:
|
130
|
+
- test/test_helper.rb
|
131
|
+
- test/validus/errors_test.rb
|
132
|
+
- test/validus_test.rb
|