whyvalidationssuckin96 1.5.5 → 1.6.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.5
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
- validatable.send(options[:attribute])
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.5.5"
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-08}
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.5.5
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-08 00:00:00 -06:00
13
+ date: 2010-03-09 00:00:00 -06:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency