dm-validations 1.1.0 → 1.2.0.rc1
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/Gemfile +8 -8
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/dm-validations.gemspec +29 -139
- data/lib/dm-validations.rb +51 -103
- data/lib/dm-validations/auto_validate.rb +104 -61
- data/lib/dm-validations/context.rb +66 -0
- data/lib/dm-validations/contextual_validators.rb +164 -53
- data/lib/dm-validations/formats/email.rb +41 -23
- data/lib/dm-validations/formats/url.rb +6 -1
- data/lib/dm-validations/support/object.rb +13 -0
- data/lib/dm-validations/validation_errors.rb +27 -19
- data/lib/dm-validations/validators/absent_field_validator.rb +11 -11
- data/lib/dm-validations/validators/acceptance_validator.rb +15 -13
- data/lib/dm-validations/validators/block_validator.rb +12 -11
- data/lib/dm-validations/validators/confirmation_validator.rb +23 -16
- data/lib/dm-validations/validators/format_validator.rb +45 -23
- data/lib/dm-validations/validators/generic_validator.rb +85 -38
- data/lib/dm-validations/validators/length_validator.rb +61 -26
- data/lib/dm-validations/validators/method_validator.rb +13 -17
- data/lib/dm-validations/validators/numeric_validator.rb +35 -35
- data/lib/dm-validations/validators/primitive_validator.rb +11 -12
- data/lib/dm-validations/validators/required_field_validator.rb +11 -13
- data/lib/dm-validations/validators/uniqueness_validator.rb +15 -14
- data/lib/dm-validations/validators/within_validator.rb +30 -12
- data/spec/fixtures/bill_of_landing.rb +5 -0
- data/spec/fixtures/llama_spaceship.rb +15 -0
- data/spec/integration/automatic_validation/custom_messages_for_inferred_validation_spec.rb +10 -0
- data/spec/integration/automatic_validation/disabling_inferred_validation_spec.rb +8 -0
- data/spec/integration/automatic_validation/inferred_length_validation_spec.rb +8 -0
- data/spec/integration/automatic_validation/inferred_uniqueness_validation_spec.rb +6 -2
- data/spec/integration/automatic_validation/inferred_within_validation_spec.rb +6 -0
- data/spec/integration/datamapper_models/association_validation_spec.rb +5 -2
- data/spec/integration/dirty_attributes/dirty_attributes_spec.rb +13 -0
- data/spec/integration/format_validator/email_format_validator_spec.rb +13 -5
- data/spec/integration/format_validator/url_format_validator_spec.rb +28 -2
- data/spec/integration/required_field_validator/association_spec.rb +5 -1
- data/spec/public/resource_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/contextual_validators/emptiness_spec.rb +10 -10
- data/spec/unit/contextual_validators/execution_spec.rb +4 -4
- data/spec/unit/validators/within_validator_spec.rb +23 -0
- metadata +81 -146
- data/lib/dm-validations/support/context.rb +0 -93
@@ -1,14 +1,12 @@
|
|
1
1
|
module DataMapper
|
2
2
|
module Validations
|
3
|
-
|
4
|
-
##
|
5
|
-
#
|
6
3
|
# @author Dirkjan Bussink
|
7
4
|
# @since 0.9
|
8
5
|
class PrimitiveTypeValidator < GenericValidator
|
6
|
+
|
9
7
|
def call(target)
|
10
8
|
value = target.validation_property_value(field_name)
|
11
|
-
property = target
|
9
|
+
property = get_resource_property(target, field_name)
|
12
10
|
|
13
11
|
return true if value.nil? || property.primitive?(value)
|
14
12
|
|
@@ -21,19 +19,22 @@ module DataMapper
|
|
21
19
|
protected
|
22
20
|
|
23
21
|
def default_error(property)
|
24
|
-
ValidationErrors.default_error_message(
|
22
|
+
ValidationErrors.default_error_message(
|
23
|
+
:primitive,
|
24
|
+
field_name,
|
25
|
+
property.primitive
|
26
|
+
)
|
25
27
|
end
|
26
28
|
|
27
29
|
end # class PrimitiveTypeValidator
|
28
30
|
|
29
31
|
module ValidatesPrimitiveType
|
30
|
-
|
31
32
|
extend Deprecate
|
32
33
|
|
33
|
-
|
34
|
-
#
|
34
|
+
# Validates that the specified attribute is of the correct primitive
|
35
|
+
# type.
|
35
36
|
#
|
36
|
-
# @example
|
37
|
+
# @example Usage
|
37
38
|
# require 'dm-validations'
|
38
39
|
#
|
39
40
|
# class Person
|
@@ -48,12 +49,10 @@ module DataMapper
|
|
48
49
|
# # casted into a Date object.
|
49
50
|
# end
|
50
51
|
def validates_primitive_type_of(*fields)
|
51
|
-
|
52
|
-
add_validator_to_context(opts, fields, DataMapper::Validations::PrimitiveTypeValidator)
|
52
|
+
validators.add(PrimitiveTypeValidator, *fields)
|
53
53
|
end
|
54
54
|
|
55
55
|
deprecate :validates_is_primitive, :validates_primitive_type_of
|
56
|
-
|
57
56
|
end # module ValidatesPresent
|
58
57
|
end # module Validations
|
59
58
|
end # module DataMapper
|
@@ -1,14 +1,12 @@
|
|
1
1
|
module DataMapper
|
2
2
|
module Validations
|
3
|
-
|
4
|
-
##
|
5
|
-
#
|
6
3
|
# @author Guy van den Berg
|
7
4
|
# @since 0.9
|
8
5
|
class PresenceValidator < GenericValidator
|
6
|
+
|
9
7
|
def call(target)
|
10
|
-
value
|
11
|
-
property = target
|
8
|
+
value = target.validation_property_value(field_name)
|
9
|
+
property = get_resource_property(target, field_name)
|
12
10
|
return true if present?(value, property)
|
13
11
|
|
14
12
|
error_message = @options[:message] || default_error(property)
|
@@ -31,11 +29,12 @@ module DataMapper
|
|
31
29
|
ValidationErrors.default_error_message(actual, field_name)
|
32
30
|
end
|
33
31
|
|
34
|
-
# Is
|
32
|
+
# Is the property a boolean property?
|
35
33
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# Returns false for
|
34
|
+
# @return [Boolean]
|
35
|
+
# Returns true for Boolean, ParanoidBoolean, TrueClass and other
|
36
|
+
# properties. Returns false for other property types or for
|
37
|
+
# non-properties.
|
39
38
|
def boolean_type?(property)
|
40
39
|
property ? property.primitive == TrueClass : false
|
41
40
|
end
|
@@ -55,9 +54,10 @@ module DataMapper
|
|
55
54
|
#
|
56
55
|
# @note
|
57
56
|
# dm-core's support lib adds the blank? method to many classes,
|
57
|
+
#
|
58
58
|
# @see lib/dm-core/support/blank.rb (dm-core) for more information.
|
59
59
|
#
|
60
|
-
# @example
|
60
|
+
# @example Usage
|
61
61
|
# require 'dm-validations'
|
62
62
|
#
|
63
63
|
# class Page
|
@@ -74,12 +74,10 @@ module DataMapper
|
|
74
74
|
# # all three attributes are !blank?
|
75
75
|
# end
|
76
76
|
def validates_presence_of(*fields)
|
77
|
-
|
78
|
-
add_validator_to_context(opts, fields, DataMapper::Validations::PresenceValidator)
|
77
|
+
validators.add(PresenceValidator, *fields)
|
79
78
|
end
|
80
79
|
|
81
80
|
deprecate :validates_present, :validates_presence_of
|
82
|
-
|
83
81
|
end # module ValidatesPresent
|
84
82
|
end # module Validations
|
85
83
|
end # module DataMapper
|
@@ -1,15 +1,16 @@
|
|
1
1
|
module DataMapper
|
2
2
|
module Validations
|
3
|
-
|
4
|
-
##
|
5
|
-
#
|
6
3
|
# @author Guy van den Berg
|
7
4
|
# @since 0.9
|
8
5
|
class UniquenessValidator < GenericValidator
|
6
|
+
|
9
7
|
include DataMapper::Assertions
|
10
8
|
|
11
9
|
def initialize(field_name, options = {})
|
12
|
-
|
10
|
+
if options.has_key?(:scope)
|
11
|
+
assert_kind_of('scope', options[:scope], Array, Symbol)
|
12
|
+
end
|
13
|
+
|
13
14
|
super
|
14
15
|
|
15
16
|
set_optional_by_default
|
@@ -33,20 +34,22 @@ module DataMapper
|
|
33
34
|
field_name => value,
|
34
35
|
}
|
35
36
|
|
36
|
-
Array(@options[:scope]).each {|subject|
|
37
|
-
|
38
|
-
|
39
|
-
else
|
40
|
-
raise ArgumentError, "Could not find property to scope by: #{subject}. Note that :unique does not currently support arbitrarily named groups, for that you should use :unique_index with an explicit validates_uniqueness_of."
|
37
|
+
Array(@options[:scope]).each { |subject|
|
38
|
+
unless target.respond_to?(subject)
|
39
|
+
raise(ArgumentError,"Could not find property to scope by: #{subject}. Note that :unique does not currently support arbitrarily named groups, for that you should use :unique_index with an explicit validates_uniqueness_of.")
|
41
40
|
end
|
41
|
+
|
42
|
+
opts[subject] = target.__send__(subject)
|
42
43
|
}
|
43
44
|
|
44
|
-
resource = DataMapper.repository(target.repository.name)
|
45
|
+
resource = DataMapper.repository(target.repository.name) do
|
46
|
+
target.model.first(opts)
|
47
|
+
end
|
45
48
|
|
46
49
|
return true if resource.nil?
|
47
|
-
|
48
50
|
target.saved? && resource.key == target.key
|
49
51
|
end
|
52
|
+
|
50
53
|
end # class UniquenessValidator
|
51
54
|
|
52
55
|
module ValidatesUniqueness
|
@@ -55,12 +58,10 @@ module DataMapper
|
|
55
58
|
# Validate the uniqueness of a field
|
56
59
|
#
|
57
60
|
def validates_uniqueness_of(*fields)
|
58
|
-
|
59
|
-
add_validator_to_context(opts, fields, DataMapper::Validations::UniquenessValidator)
|
61
|
+
validators.add(UniquenessValidator, *fields)
|
60
62
|
end
|
61
63
|
|
62
64
|
deprecate :validates_is_unique, :validates_uniqueness_of
|
63
|
-
|
64
65
|
end # module ValidatesIsUnique
|
65
66
|
end # module Validations
|
66
67
|
end # module DataMapper
|
@@ -1,8 +1,5 @@
|
|
1
1
|
module DataMapper
|
2
2
|
module Validations
|
3
|
-
|
4
|
-
##
|
5
|
-
#
|
6
3
|
# @author Guy van den Berg
|
7
4
|
# @since 0.9
|
8
5
|
class WithinValidator < GenericValidator
|
@@ -18,8 +15,10 @@ module DataMapper
|
|
18
15
|
return true if optional?(value)
|
19
16
|
return true if @options[:set].include?(value)
|
20
17
|
|
18
|
+
n = 1.0/0
|
21
19
|
set = @options[:set]
|
22
20
|
msg = @options[:message]
|
21
|
+
|
23
22
|
if set.is_a?(Range)
|
24
23
|
if set.first != -n && set.last != n
|
25
24
|
error_message = msg || ValidationErrors.default_error_message(:value_between, field_name, set.first, set.last)
|
@@ -29,7 +28,7 @@ module DataMapper
|
|
29
28
|
error_message = msg || ValidationErrors.default_error_message(:greater_than_or_equal_to, field_name, set.first)
|
30
29
|
end
|
31
30
|
else
|
32
|
-
error_message = msg || ValidationErrors.default_error_message(:inclusion, field_name, set.join(', '))
|
31
|
+
error_message = msg || ValidationErrors.default_error_message(:inclusion, field_name, set.to_a.join(', '))
|
33
32
|
end
|
34
33
|
|
35
34
|
add_error(target, error_message, field_name)
|
@@ -37,20 +36,39 @@ module DataMapper
|
|
37
36
|
false
|
38
37
|
end
|
39
38
|
|
40
|
-
|
41
|
-
1.0/0
|
42
|
-
end
|
39
|
+
|
43
40
|
end # class WithinValidator
|
44
41
|
|
45
42
|
module ValidatesWithin
|
46
|
-
|
47
|
-
#
|
43
|
+
##
|
44
|
+
# Validates that the value of a field is within a range/set.
|
45
|
+
#
|
46
|
+
# This validation is defined by passing a field along with a :set
|
47
|
+
# parameter. The :set can be a Range or any object which responds
|
48
|
+
# to the #include? method (an array, for example).
|
48
49
|
#
|
50
|
+
# @example Usage
|
51
|
+
# require 'dm-validations'
|
52
|
+
#
|
53
|
+
# class Review
|
54
|
+
# include DataMapper::Resource
|
55
|
+
#
|
56
|
+
# STATES = ['new', 'in_progress', 'published', 'archived']
|
57
|
+
#
|
58
|
+
# property :title, String
|
59
|
+
# property :body, String
|
60
|
+
# property :review_state, String
|
61
|
+
# property :rating, Integer
|
62
|
+
#
|
63
|
+
# validates_within :review_state, :set => STATES
|
64
|
+
# validates_within :rating, :set => 1..5
|
65
|
+
#
|
66
|
+
# # a call to valid? will return false unless
|
67
|
+
# # the two properties conform to their sets
|
68
|
+
# end
|
49
69
|
def validates_within(*fields)
|
50
|
-
|
51
|
-
add_validator_to_context(opts, fields, DataMapper::Validations::WithinValidator)
|
70
|
+
validators.add(WithinValidator, *fields)
|
52
71
|
end
|
53
|
-
|
54
72
|
end # module ValidatesWithin
|
55
73
|
end # module Validations
|
56
74
|
end # module DataMapper
|
@@ -20,6 +20,7 @@ module DataMapper
|
|
20
20
|
property :email, String, :auto_validation => false
|
21
21
|
property :username, String, :auto_validation => false
|
22
22
|
property :url, String, :auto_validation => false
|
23
|
+
property :bank_url, URI, :auto_validation => false
|
23
24
|
property :code, String, :auto_validation => false, :default => "123456"
|
24
25
|
|
25
26
|
#
|
@@ -37,6 +38,10 @@ module DataMapper
|
|
37
38
|
validates_format_of :username, :with => /[a-z]/, :message => 'Username must have at least one letter', :allow_nil => true
|
38
39
|
validates_format_of :code, :with => /\d{5,6}/, :message => 'Code format is invalid'
|
39
40
|
end
|
41
|
+
|
42
|
+
class SurrenderBillOfLading < BillOfLading
|
43
|
+
validates_format_of :bank_url, :as => :url, :allow_nil => false, :allow_blank => false
|
44
|
+
end
|
40
45
|
end # Fixtures
|
41
46
|
end # Validations
|
42
47
|
end # DataMapper
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validations
|
3
|
+
module Fixtures
|
4
|
+
class LlamaSpaceship
|
5
|
+
include DataMapper::Resource
|
6
|
+
|
7
|
+
property :id, Serial
|
8
|
+
property :type, String
|
9
|
+
property :color, String
|
10
|
+
|
11
|
+
validates_format_of :color, :with => /^red|black$/, :if => Proc.new { |spaceship| spaceship.type == "standard" }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,6 +5,11 @@ describe 'Inferred validations' do
|
|
5
5
|
it "allow overriding a single error message" do
|
6
6
|
custom_boat = Class.new do
|
7
7
|
include DataMapper::Resource
|
8
|
+
|
9
|
+
def self.name
|
10
|
+
'Boat'
|
11
|
+
end
|
12
|
+
|
8
13
|
property :id, DataMapper::Property::Serial
|
9
14
|
property :name, String, :required => true, :message => "This boat must have name"
|
10
15
|
end
|
@@ -16,6 +21,11 @@ describe 'Inferred validations' do
|
|
16
21
|
it "should have correct error messages" do
|
17
22
|
custom_boat = Class.new do
|
18
23
|
include DataMapper::Resource
|
24
|
+
|
25
|
+
def self.name
|
26
|
+
'Boat'
|
27
|
+
end
|
28
|
+
|
19
29
|
property :id, DataMapper::Property::Serial
|
20
30
|
property :name, String, :required => true, :length => 5..20, :format => /^[a-z]+$/,
|
21
31
|
:messages => {
|
@@ -6,6 +6,10 @@ describe "A class with inferred validations disabled for all properties with an
|
|
6
6
|
@klass = Class.new do
|
7
7
|
include DataMapper::Resource
|
8
8
|
|
9
|
+
def self.name
|
10
|
+
'InferredValidation'
|
11
|
+
end
|
12
|
+
|
9
13
|
property :id, DataMapper::Property::Serial, :auto_validation => false
|
10
14
|
property :name, String, :required => true, :auto_validation => false
|
11
15
|
property :bool, DataMapper::Property::Boolean, :required => true, :auto_validation => false
|
@@ -25,6 +29,10 @@ describe "A class with inferred validations disabled for all properties with a b
|
|
25
29
|
@klass = Class.new do
|
26
30
|
include DataMapper::Resource
|
27
31
|
|
32
|
+
def self.name
|
33
|
+
'InferredValidation'
|
34
|
+
end
|
35
|
+
|
28
36
|
without_auto_validations do
|
29
37
|
property :id, DataMapper::Property::Serial
|
30
38
|
property :name, String, :required => true
|
@@ -124,6 +124,14 @@ describe 'DataMapper::Validations::Fixtures::SmsMessage' do
|
|
124
124
|
end
|
125
125
|
|
126
126
|
describe 'with an infinitely long note' do
|
127
|
+
before do
|
128
|
+
@original = @model.class.properties[:body]
|
129
|
+
end
|
130
|
+
|
131
|
+
after do
|
132
|
+
@model.class.property(@original.name, @original.class, @original.options)
|
133
|
+
end
|
134
|
+
|
127
135
|
it "should raise when trying to set the upper bound of a property length range to Infinity" do
|
128
136
|
expected_msg = "Infinity is no valid upper bound for a length range"
|
129
137
|
lambda {
|
@@ -7,7 +7,9 @@ describe 'uniqueness' do
|
|
7
7
|
@klass = Class.new do
|
8
8
|
include DataMapper::Resource
|
9
9
|
|
10
|
-
|
10
|
+
def self.name
|
11
|
+
'UniqueEventsSingle'
|
12
|
+
end
|
11
13
|
|
12
14
|
property :id, Integer, :key => true
|
13
15
|
property :start_year, Integer, :unique => true
|
@@ -28,7 +30,9 @@ describe 'uniqueness' do
|
|
28
30
|
@klass = Class.new do
|
29
31
|
include DataMapper::Resource
|
30
32
|
|
31
|
-
|
33
|
+
def self.name
|
34
|
+
'UniqueEventsMultiple'
|
35
|
+
end
|
32
36
|
|
33
37
|
property :id, Integer, :key => true
|
34
38
|
property :start_year, Integer, :unique => :years
|
@@ -8,6 +8,12 @@ describe 'A model with a :set & :default options on a property' do
|
|
8
8
|
property :id, DataMapper::Property::Serial
|
9
9
|
property :limited, String, :set => %w[ foo bar bang ], :default => 'foo'
|
10
10
|
end
|
11
|
+
|
12
|
+
DataMapper.finalize
|
13
|
+
|
14
|
+
if DataMapper.respond_to?(:auto_migrate!)
|
15
|
+
DataMapper.auto_migrate!
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
19
|
describe "without value on that property" do
|
@@ -5,10 +5,13 @@ describe 'DataMapper::Validations::Fixtures::Product' do
|
|
5
5
|
DataMapper::Validations::Fixtures::ProductCompany.auto_migrate!
|
6
6
|
DataMapper::Validations::Fixtures::Product.auto_migrate!
|
7
7
|
|
8
|
-
|
8
|
+
parent_model = DataMapper::Validations::Fixtures::ProductCompany
|
9
|
+
@parent = parent_model.new(:title => "Apple", :flagship_product => "Macintosh")
|
9
10
|
@parent.should be_valid
|
11
|
+
@parent.save.should be_true
|
10
12
|
|
11
|
-
|
13
|
+
model_model = DataMapper::Validations::Fixtures::Product
|
14
|
+
@model = model_model.new(:name => "MacBook Pro", :company => @parent)
|
12
15
|
@model.should be_valid
|
13
16
|
end
|
14
17
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'DataMapper::Validations::Fixtures::LlamaSpaceship' do
|
4
|
+
before :all do
|
5
|
+
DataMapper::Validations::Fixtures::LlamaSpaceship.auto_migrate!
|
6
|
+
end
|
7
|
+
|
8
|
+
it "validates even non dirty attributes" do
|
9
|
+
spaceship = DataMapper::Validations::Fixtures::LlamaSpaceship.create(:type => "custom", :color => "pink")
|
10
|
+
spaceship.type = "standard"
|
11
|
+
spaceship.should_not be_valid
|
12
|
+
end
|
13
|
+
end
|
@@ -41,7 +41,8 @@ describe 'DataMapper::Validations::Fixtures::BillOfLading' do
|
|
41
41
|
'Max@Job 3:14',
|
42
42
|
'Job@Book of Job',
|
43
43
|
'test@localhost',
|
44
|
-
'J. P. \'s-Gravezande, a.k.a. The Hacker!@example.com'
|
44
|
+
'J. P. \'s-Gravezande, a.k.a. The Hacker!@example.com',
|
45
|
+
"test@example.com\nsomething after the newline"].each do |email|
|
45
46
|
describe "with email value of #{email} (non RFC2822 compliant)" do
|
46
47
|
before :all do
|
47
48
|
@model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:email => email))
|
@@ -56,10 +57,17 @@ describe 'DataMapper::Validations::Fixtures::BillOfLading' do
|
|
56
57
|
@model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:email => 'pelé@gmail.com'))
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
it 'should
|
62
|
-
@model.
|
60
|
+
if (RUBY_VERSION == '1.9.2' && RUBY_ENGINE == 'jruby') || RUBY_VERSION == '1.9.3'
|
61
|
+
# Not supported on jruby 1.9 or 1.9.3 yet - see formats/email.rb
|
62
|
+
it 'should not raise an error' do
|
63
|
+
lambda { @model.valid? }.should_not raise_error
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# Unicode emails not supported on MRI18
|
67
|
+
unless !defined?(RUBY_ENGINE) && RUBY_VERSION == '1.8.7'
|
68
|
+
it 'should behave like valid model' do
|
69
|
+
@model.should be_valid
|
70
|
+
end
|
63
71
|
end
|
64
72
|
end
|
65
73
|
end
|