whyvalidationssuckin96 1.5.5 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0
|
@@ -1,44 +1,79 @@
|
|
1
1
|
module WhyValidationsSuckIn96
|
2
|
-
# A mixin to help handle the most common case of validating a single attribute on an object. This module has a
|
2
|
+
# A mixin to help handle the most common case of validating a single attribute on an object. This module has a
|
3
3
|
# dependency on SkippableValidation that will most likely be removed in future releases, but is something to be
|
4
4
|
# aware of currently.
|
5
5
|
module AttributeBasedValidation
|
6
|
-
|
6
|
+
|
7
7
|
# An initializer for a validation that checks to see if the required options have been passed for
|
8
8
|
# attribute based validation to work as expected.
|
9
9
|
# @param [Object] validatable An object to be validated
|
10
10
|
# @param [Hash] options The options to set up the validation with
|
11
11
|
# @option options [Symbol] :attribute The attribute on the validatable object to validate against
|
12
|
+
# @option options [true, false] :array Specifies the attribute is an array of values to validate individually
|
12
13
|
# @option options [true, false] :allow_nil If true, skips validation of the value of the attribute is #nil?
|
13
14
|
# @option options [true, false] :allow_blank If true, skips validation of the value of the attribute is #blank?
|
15
|
+
# @option options [true, false] :allow_empty If true, along with :array, skips validation if the array is empty
|
14
16
|
def initialize(validatable, options = {})
|
15
17
|
raise(ArgumentError, "The attribute to validate must be specified as :attribute") unless options[:attribute]
|
18
|
+
@pos = 0 if options[:array]
|
16
19
|
super
|
17
20
|
end
|
18
|
-
|
21
|
+
|
19
22
|
# The attribute to validate against
|
20
23
|
def attribute
|
21
24
|
options[:attribute]
|
22
25
|
end
|
23
|
-
|
26
|
+
|
24
27
|
# The value of the attribute to validate against
|
25
28
|
def attribute_value
|
26
|
-
|
29
|
+
if options[:array]
|
30
|
+
validatable.send(options[:attribute])[@pos]
|
31
|
+
else
|
32
|
+
validatable.send(options[:attribute])
|
33
|
+
end
|
27
34
|
end
|
28
|
-
|
35
|
+
|
29
36
|
# A default validate implementation that skips on #nil?/#blank? attribute values if :allow_nil or :allow_blank
|
30
37
|
# have been set.
|
31
38
|
def validate
|
32
|
-
skip if skip_on_blank? || skip_on_nil?
|
39
|
+
skip if skip_on_empty? || skip_on_blank? || skip_on_nil?
|
33
40
|
super
|
34
41
|
end
|
35
|
-
|
42
|
+
|
43
|
+
# Performs the validation, returning true or false if the validation passes or fails,
|
44
|
+
# or nil if the validation will not run.
|
45
|
+
# @return [true, false, nil]
|
46
|
+
def validates?
|
47
|
+
if options[:array]
|
48
|
+
return @passed = nil if skip_on_empty?
|
49
|
+
reset
|
50
|
+
@pos = 0
|
51
|
+
statuses = []
|
52
|
+
while validating?
|
53
|
+
status = super
|
54
|
+
@pos += 1
|
55
|
+
statuses << status
|
56
|
+
end
|
57
|
+
@passed = statuses.all?
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
36
63
|
private
|
37
64
|
|
65
|
+
def validating?
|
66
|
+
(@pos + 1) <= Array(validatable.send(options[:attribute])).size
|
67
|
+
end
|
68
|
+
|
69
|
+
def skip_on_empty?
|
70
|
+
options[:array] && options[:allow_empty] && Array(validatable.send(options[:attribute])).empty?
|
71
|
+
end
|
72
|
+
|
38
73
|
def skip_on_nil?
|
39
74
|
options[:allow_nil] && attribute_value.nil?
|
40
75
|
end
|
41
|
-
|
76
|
+
|
42
77
|
def skip_on_blank?
|
43
78
|
options[:allow_blank] && attribute_value.blank?
|
44
79
|
end
|
@@ -1,41 +1,41 @@
|
|
1
1
|
module WhyValidationsSuckIn96
|
2
|
-
|
2
|
+
|
3
3
|
# Base class to use when implementing validations.
|
4
4
|
class Validation
|
5
|
-
|
5
|
+
|
6
6
|
# A hash of default options for the validation to use.
|
7
7
|
DefaultOptions = {}
|
8
|
-
|
8
|
+
|
9
9
|
# The options the validation was initialized with
|
10
10
|
attr_accessor :options
|
11
|
-
|
11
|
+
|
12
12
|
# The object the validation is validating
|
13
13
|
attr_reader :validatable
|
14
|
-
|
14
|
+
|
15
15
|
class << self
|
16
16
|
attr_accessor :name
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
# @param [Object] validatable An object to be validated
|
20
20
|
# @param [Hash] options The options to set up the validation with
|
21
21
|
def initialize(validatable, options = {})
|
22
22
|
@validatable = validatable
|
23
23
|
@options = self.class::DefaultOptions.merge(options)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Creates a new subclass of this class, used when defining custom validations with a block
|
27
27
|
def self.new_subclass(name, def_block)
|
28
28
|
Class.new(self) do
|
29
29
|
self.name = name.to_sym
|
30
30
|
define_method(:validate, &def_block)
|
31
31
|
private :validate
|
32
|
-
|
32
|
+
|
33
33
|
def inspect
|
34
34
|
"#<WhyValidationsSuckIn96::Validation subclass for validating '#{self.class.name}'> #{super}"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# Has this validation passed?
|
40
40
|
# @return [true, false]
|
41
41
|
def passed?
|
@@ -47,13 +47,13 @@ module WhyValidationsSuckIn96
|
|
47
47
|
def failed?
|
48
48
|
@passed == false
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# Has this validation run?
|
52
52
|
# @return [true, false]
|
53
53
|
def has_run?
|
54
54
|
@passed != nil
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Performs the validation, returning true or false if the validation passes or fails,
|
58
58
|
# or nil if the validation will not run.
|
59
59
|
# @return [true, false, nil]
|
@@ -64,25 +64,25 @@ module WhyValidationsSuckIn96
|
|
64
64
|
pass
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# The failure message for this validation.
|
69
69
|
def message
|
70
70
|
@options[:message] || "failed validation"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
private
|
74
|
-
|
74
|
+
|
75
75
|
def reset
|
76
76
|
@passed = nil
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def pass
|
80
80
|
throw :validation_done, true
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
def fail
|
84
84
|
throw :validation_done, false
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
end # Validation
|
88
88
|
end # WhyValidationsSuckIn96
|
@@ -3,56 +3,102 @@ require 'whyvalidationssuckin96/attribute_based_validation'
|
|
3
3
|
|
4
4
|
context "attribute based validation mixin" do
|
5
5
|
context "when mixed into a class" do
|
6
|
-
|
6
|
+
|
7
7
|
setup do
|
8
8
|
Class.new(WhyValidationsSuckIn96::Validation) do
|
9
9
|
include WhyValidationsSuckIn96::SkippableValidation
|
10
10
|
include WhyValidationsSuckIn96::AttributeBasedValidation
|
11
|
-
|
11
|
+
|
12
12
|
def validate
|
13
13
|
super
|
14
14
|
pass
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
end # Class.new
|
18
18
|
end # setup
|
19
|
-
|
19
|
+
|
20
20
|
should "fail if no attribute is specified during construction" do
|
21
21
|
topic.new(Object.new)
|
22
22
|
end.raises(ArgumentError, "The attribute to validate must be specified as :attribute")
|
23
|
-
|
23
|
+
|
24
24
|
should "add an attribute accessor" do
|
25
25
|
topic.new(Object.new, :attribute => :foo).attribute
|
26
26
|
end.equals(:foo)
|
27
|
-
|
27
|
+
|
28
28
|
context "when using :allow_nil" do
|
29
|
-
|
29
|
+
|
30
30
|
should "skip validation if the validatable object is #nil?" do
|
31
31
|
inst = topic.new(OpenStruct.new(:test => nil), :allow_nil => true, :attribute => :test)
|
32
32
|
inst.validates?
|
33
33
|
inst.has_run?
|
34
34
|
end.equals(false)
|
35
|
-
|
35
|
+
|
36
36
|
should "not skip validation of the validatable object is non-#nil?" do
|
37
37
|
inst = topic.new(OpenStruct.new(:test => Object.new), :allow_nil => true, :attribute => :test)
|
38
38
|
inst.validates?
|
39
39
|
inst.has_run?
|
40
40
|
end
|
41
41
|
end # when using :allow_nil
|
42
|
-
|
42
|
+
|
43
43
|
context "when using :allow_blank" do
|
44
44
|
should "skip validation if the validatable object is #blank?" do
|
45
45
|
inst = topic.new(OpenStruct.new(:test => ""), :allow_blank => true, :attribute => :test)
|
46
46
|
inst.validates?
|
47
47
|
inst.has_run?
|
48
48
|
end.equals(false)
|
49
|
-
|
49
|
+
|
50
50
|
should "not skip validation if the validatable object is non-#blank?" do
|
51
51
|
inst = topic.new(OpenStruct.new(:test => "bzzt"), :allow_blank => true, :attribute => :test)
|
52
52
|
inst.validates?
|
53
53
|
inst.has_run?
|
54
54
|
end
|
55
55
|
end # when using :allow_blank
|
56
|
-
|
56
|
+
|
57
|
+
context "when using :array" do
|
58
|
+
setup do
|
59
|
+
Class.new(WhyValidationsSuckIn96::Validation) do
|
60
|
+
include WhyValidationsSuckIn96::SkippableValidation
|
61
|
+
include WhyValidationsSuckIn96::AttributeBasedValidation
|
62
|
+
|
63
|
+
def validate
|
64
|
+
super
|
65
|
+
attribute_value.even? ? pass : fail
|
66
|
+
end
|
67
|
+
|
68
|
+
end # Class.new
|
69
|
+
end
|
70
|
+
|
71
|
+
should "fail if any item doesnt validate" do
|
72
|
+
inst = topic.new(OpenStruct.new(:test => [2,4,1,6]), :attribute => :test, :array => true)
|
73
|
+
inst.validates?
|
74
|
+
end.equals(false)
|
75
|
+
|
76
|
+
should "pass if all items validate" do
|
77
|
+
inst = topic.new(OpenStruct.new(:test => [2,4,6]), :attribute => :test, :array => true)
|
78
|
+
inst.validates?
|
79
|
+
end
|
80
|
+
|
81
|
+
should "still pass if the collection state changes between validation calls" do
|
82
|
+
validatable = OpenStruct.new(:test => [1,2,4,6])
|
83
|
+
inst = topic.new(validatable, :allow_empty => true, :attribute => :test, :array => true)
|
84
|
+
first_failed = !inst.validates?
|
85
|
+
validatable.test = [2,4,6]
|
86
|
+
first_failed && inst.validates?
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with :allow_empty" do
|
90
|
+
should "skip validation if the array is empty" do
|
91
|
+
inst = topic.new(OpenStruct.new(:test => []), :allow_empty => true, :attribute => :test, :array => true)
|
92
|
+
inst.validates?
|
93
|
+
inst.has_run?
|
94
|
+
end.equals(false)
|
95
|
+
|
96
|
+
should "not skip validation of the validatable object is non-#empty?" do
|
97
|
+
inst = topic.new(OpenStruct.new(:test => [0]), :allow_empty => true, :attribute => :test, :array => true)
|
98
|
+
inst.validates?
|
99
|
+
inst.has_run?
|
100
|
+
end
|
101
|
+
end # with :allow_empty
|
102
|
+
end # when using :array
|
57
103
|
end # when mixed into a class
|
58
104
|
end # skippable validation mixin
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{whyvalidationssuckin96}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["gabrielg", "douglasmeyer"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-09}
|
13
13
|
s.description = %q{A library for setting up model validations, such as in ActiveRecord.}
|
14
14
|
s.email = %q{gabriel.gironda@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: whyvalidationssuckin96
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gabrielg
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2010-03-
|
13
|
+
date: 2010-03-09 00:00:00 -06:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|