dm-validations 0.9.11 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History.rdoc} +10 -3
- data/LICENSE +1 -0
- data/Manifest.txt +103 -33
- data/README.rdoc +172 -0
- data/Rakefile +4 -5
- data/lib/dm-validations.rb +73 -75
- data/lib/dm-validations/auto_validate.rb +98 -56
- data/lib/dm-validations/contextual_validators.rb +37 -14
- data/lib/dm-validations/exceptions.rb +3 -0
- data/lib/dm-validations/formats/url.rb +3 -1
- data/lib/dm-validations/support/context.rb +54 -0
- data/lib/dm-validations/validation_errors.rb +51 -27
- data/lib/dm-validations/{absent_field_validator.rb → validators/absent_field_validator.rb} +2 -8
- data/lib/dm-validations/{acceptance_validator.rb → validators/acceptance_validator.rb} +7 -7
- data/lib/dm-validations/{block_validator.rb → validators/block_validator.rb} +0 -0
- data/lib/dm-validations/{confirmation_validator.rb → validators/confirmation_validator.rb} +7 -7
- data/lib/dm-validations/{format_validator.rb → validators/format_validator.rb} +10 -16
- data/lib/dm-validations/{generic_validator.rb → validators/generic_validator.rb} +28 -6
- data/lib/dm-validations/validators/length_validator.rb +214 -0
- data/lib/dm-validations/validators/method_validator.rb +68 -0
- data/lib/dm-validations/validators/numeric_validator.rb +171 -0
- data/lib/dm-validations/{primitive_validator.rb → validators/primitive_validator.rb} +2 -7
- data/lib/dm-validations/{required_field_validator.rb → validators/required_field_validator.rb} +0 -6
- data/lib/dm-validations/{uniqueness_validator.rb → validators/uniqueness_validator.rb} +9 -20
- data/lib/dm-validations/{within_validator.rb → validators/within_validator.rb} +4 -4
- data/lib/dm-validations/version.rb +1 -1
- data/spec/fixtures/barcode.rb +32 -0
- data/spec/fixtures/basketball_court.rb +58 -0
- data/spec/fixtures/basketball_player.rb +37 -0
- data/spec/fixtures/beta_tester_account.rb +33 -0
- data/spec/fixtures/bill_of_landing.rb +42 -0
- data/spec/fixtures/boat_dock.rb +26 -0
- data/spec/fixtures/city.rb +25 -0
- data/spec/fixtures/company.rb +95 -0
- data/spec/fixtures/corporate_world.rb +47 -0
- data/spec/fixtures/country.rb +25 -0
- data/spec/fixtures/currency.rb +42 -0
- data/spec/fixtures/ethernet_frame.rb +56 -0
- data/spec/fixtures/event.rb +44 -0
- data/spec/fixtures/g3_concert.rb +57 -0
- data/spec/fixtures/jabberwock.rb +27 -0
- data/spec/fixtures/kayak.rb +28 -0
- data/spec/fixtures/lernean_hydra.rb +39 -0
- data/spec/fixtures/mathematical_function.rb +34 -0
- data/spec/fixtures/memory_object.rb +30 -0
- data/spec/fixtures/mittelschnauzer.rb +35 -0
- data/spec/fixtures/motor_launch.rb +21 -0
- data/spec/fixtures/page.rb +32 -0
- data/spec/fixtures/phone_number.rb +28 -0
- data/spec/fixtures/pirogue.rb +28 -0
- data/spec/fixtures/programming_language.rb +83 -0
- data/spec/fixtures/reservation.rb +38 -0
- data/spec/fixtures/scm_operation.rb +67 -0
- data/spec/fixtures/sms_message.rb +22 -0
- data/spec/fixtures/udp_packet.rb +49 -0
- data/spec/integration/absent_field_validator/absent_field_validator_spec.rb +86 -0
- data/spec/integration/absent_field_validator/spec_helper.rb +7 -0
- data/spec/integration/acceptance_validator/acceptance_validator_spec.rb +196 -0
- data/spec/integration/acceptance_validator/spec_helper.rb +7 -0
- data/spec/integration/automatic_validation/custom_messages_for_inferred_validation_spec.rb +47 -0
- data/spec/integration/automatic_validation/disabling_inferred_validation_spec.rb +41 -0
- data/spec/integration/automatic_validation/inferred_boolean_properties_validation_spec.rb +104 -0
- data/spec/integration/automatic_validation/inferred_float_property_validation_spec.rb +35 -0
- data/spec/integration/automatic_validation/inferred_format_validation_spec.rb +33 -0
- data/spec/integration/automatic_validation/inferred_integer_properties_validation_spec.rb +73 -0
- data/spec/integration/automatic_validation/inferred_length_validation_spec.rb +121 -0
- data/spec/integration/automatic_validation/inferred_presence_validation_spec.rb +41 -0
- data/spec/integration/automatic_validation/inferred_primitive_validation_spec.rb +20 -0
- data/spec/integration/automatic_validation/inferred_within_validation_spec.rb +33 -0
- data/spec/integration/automatic_validation/spec_helper.rb +74 -0
- data/spec/integration/block_validator/block_validator_spec.rb +32 -0
- data/spec/integration/block_validator/spec_helper.rb +5 -0
- data/spec/integration/conditional_validation/if_condition_spec.rb +61 -0
- data/spec/integration/conditional_validation/spec_helper.rb +5 -0
- data/spec/integration/confirmation_validator/confirmation_validator_spec.rb +74 -0
- data/spec/integration/confirmation_validator/spec_helper.rb +5 -0
- data/spec/integration/datamapper_models/association_validation_spec.rb +23 -0
- data/spec/integration/datamapper_models/inheritance_spec.rb +78 -0
- data/spec/integration/duplicated_validations/duplicated_validations_spec.rb +22 -0
- data/spec/integration/duplicated_validations/spec_helper.rb +5 -0
- data/spec/integration/format_validator/email_format_validator_spec.rb +113 -0
- data/spec/integration/format_validator/format_validator_spec.rb +60 -0
- data/spec/integration/format_validator/regexp_validator_spec.rb +29 -0
- data/spec/integration/format_validator/spec_helper.rb +5 -0
- data/spec/integration/format_validator/url_format_validator_spec.rb +63 -0
- data/spec/integration/length_validator/default_value_spec.rb +12 -0
- data/spec/integration/length_validator/equality_spec.rb +79 -0
- data/spec/integration/length_validator/error_message_spec.rb +15 -18
- data/spec/integration/length_validator/maximum_spec.rb +40 -24
- data/spec/integration/length_validator/minimum_spec.rb +32 -21
- data/spec/integration/length_validator/range_spec.rb +50 -60
- data/spec/integration/length_validator/spec_helper.rb +7 -12
- data/spec/integration/method_validator/method_validator_spec.rb +239 -0
- data/spec/integration/method_validator/spec_helper.rb +5 -0
- data/spec/integration/numeric_validator/equality_with_float_type_spec.rb +61 -0
- data/spec/integration/numeric_validator/equality_with_integer_type_spec.rb +37 -0
- data/spec/integration/numeric_validator/float_type_spec.rb +42 -56
- data/spec/integration/numeric_validator/gt_with_float_type_spec.rb +35 -0
- data/spec/integration/numeric_validator/gte_with_float_type_spec.rb +35 -0
- data/spec/integration/numeric_validator/integer_only_true_spec.rb +3 -6
- data/spec/integration/numeric_validator/integer_type_spec.rb +8 -24
- data/spec/integration/numeric_validator/lt_with_float_type_spec.rb +35 -0
- data/spec/integration/numeric_validator/lte_with_float_type_spec.rb +35 -0
- data/spec/integration/numeric_validator/spec_helper.rb +5 -77
- data/spec/integration/primitive_validator/primitive_validator_spec.rb +90 -0
- data/spec/integration/primitive_validator/spec_helper.rb +5 -0
- data/spec/integration/pure_ruby_objects/plain_old_ruby_object_validation_spec.rb +118 -0
- data/spec/integration/required_field_validator/association_spec.rb +5 -8
- data/spec/integration/required_field_validator/boolean_type_value_spec.rb +4 -7
- data/spec/integration/required_field_validator/date_type_value_spec.rb +3 -6
- data/spec/integration/required_field_validator/datetime_type_value_spec.rb +3 -6
- data/spec/integration/required_field_validator/float_type_value_spec.rb +3 -6
- data/spec/integration/required_field_validator/integer_type_value_spec.rb +2 -5
- data/spec/integration/required_field_validator/plain_old_ruby_object_spec.rb +5 -8
- data/spec/integration/required_field_validator/shared_examples.rb +1 -1
- data/spec/integration/required_field_validator/spec_helper.rb +6 -67
- data/spec/integration/required_field_validator/string_type_value_spec.rb +2 -5
- data/spec/integration/required_field_validator/text_type_value_spec.rb +2 -5
- data/spec/integration/shared/default_validation_context.rb +13 -0
- data/spec/integration/shared/valid_and_invalid_model.rb +27 -0
- data/spec/integration/uniqueness_validator/spec_helper.rb +5 -0
- data/spec/integration/uniqueness_validator/uniqueness_validator_spec.rb +114 -0
- data/spec/integration/within_validator/spec_helper.rb +5 -0
- data/spec/integration/within_validator/within_validator_spec.rb +164 -0
- data/spec/public/resource_spec.rb +68 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -4
- data/spec/unit/contextual_validators/emptiness_spec.rb +50 -0
- data/spec/unit/contextual_validators/execution_spec.rb +55 -0
- data/spec/unit/contextual_validators/spec_helper.rb +37 -0
- data/spec/unit/generic_validator/equality_operator_spec.rb +26 -0
- data/spec/unit/validation_errors/adding_spec.rb +54 -0
- data/spec/unit/validation_errors/emptiness_spec.rb +38 -0
- data/spec/unit/validation_errors/enumerable_spec.rb +32 -0
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +118 -55
- data/README.txt +0 -72
- data/lib/dm-validations/custom_validator.rb +0 -72
- data/lib/dm-validations/length_validator.rb +0 -113
- data/lib/dm-validations/method_validator.rb +0 -68
- data/lib/dm-validations/numeric_validator.rb +0 -83
- data/spec/integration/absent_field_validator_spec.rb +0 -36
- data/spec/integration/acceptance_validator_spec.rb +0 -87
- data/spec/integration/auto_validate_spec.rb +0 -342
- data/spec/integration/block_validator_spec.rb +0 -30
- data/spec/integration/confirmation_validator_spec.rb +0 -105
- data/spec/integration/contextual_validators_spec.rb +0 -27
- data/spec/integration/custom_validator_spec.rb +0 -9
- data/spec/integration/format_validator_spec.rb +0 -193
- data/spec/integration/generic_validator_spec.rb +0 -17
- data/spec/integration/length_validator/valid_objects_spec.rb +0 -13
- data/spec/integration/method_validator_spec.rb +0 -58
- data/spec/integration/numeric_validator_spec.rb +0 -253
- data/spec/integration/primitive_validator_spec.rb +0 -30
- data/spec/integration/uniqueness_validator_spec.rb +0 -97
- data/spec/integration/validation_errors_spec.rb +0 -18
- data/spec/integration/validation_spec.rb +0 -404
- data/spec/integration/within_validator_spec.rb +0 -79
@@ -1,29 +1,36 @@
|
|
1
1
|
module DataMapper
|
2
2
|
class Property
|
3
3
|
# for options_with_message
|
4
|
-
|
4
|
+
OPTIONS << :message << :messages << :set
|
5
5
|
end
|
6
6
|
|
7
7
|
module Validate
|
8
8
|
module AutoValidate
|
9
|
+
@disable_auto_validations = false
|
10
|
+
|
9
11
|
# adds message for validator
|
10
12
|
def options_with_message(base_options, property, validator_name)
|
11
13
|
options = base_options.clone
|
12
|
-
opts
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
elsif opts[:message]
|
20
|
-
opts[:message]
|
21
|
-
else
|
22
|
-
nil
|
14
|
+
opts = property.options
|
15
|
+
|
16
|
+
if opts.key?(:messages)
|
17
|
+
options[:message] = opts[:messages][validator_name]
|
18
|
+
elsif opts.key?(:message)
|
19
|
+
options[:message] = opts[:message]
|
23
20
|
end
|
21
|
+
|
24
22
|
options
|
25
23
|
end
|
26
24
|
|
25
|
+
attr_reader :disable_auto_validations
|
26
|
+
|
27
|
+
# disables generation of validations for
|
28
|
+
# duration of given block
|
29
|
+
def without_auto_validations(&block)
|
30
|
+
@disable_auto_validations = true
|
31
|
+
block.call
|
32
|
+
@disable_auto_validations = false
|
33
|
+
end
|
27
34
|
|
28
35
|
##
|
29
36
|
# Auto-generate validations for a given property. This will only occur
|
@@ -37,8 +44,8 @@ module DataMapper
|
|
37
44
|
# validates_presence_of validator to be automatically created on
|
38
45
|
# the property
|
39
46
|
#
|
40
|
-
# :
|
41
|
-
# Setting the option :
|
47
|
+
# :length => 20
|
48
|
+
# Setting the option :length causes a validates_length_of
|
42
49
|
# validator to be automatically created on the property. If the
|
43
50
|
# value is a Integer the validation will set :maximum => value if
|
44
51
|
# the value is a Range the validation will set :within => value
|
@@ -76,78 +83,113 @@ module DataMapper
|
|
76
83
|
# It is just shortcut if only one validation option is set
|
77
84
|
#
|
78
85
|
def auto_generate_validations(property)
|
79
|
-
|
80
|
-
|
86
|
+
return if disabled_auto_validations? || skip_auto_validation_for?(property)
|
87
|
+
|
88
|
+
# all auto-validations (aside from presence) should skip
|
89
|
+
# validation when the value is nil
|
90
|
+
opts = { :allow_nil => true }
|
81
91
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
92
|
+
if property.options.has_key?(:validates)
|
93
|
+
opts[:context] = property.options[:validates]
|
94
|
+
end
|
95
|
+
|
96
|
+
infer_presence_validation_for(property, opts.dup)
|
97
|
+
infer_length_validation_for(property, opts.dup)
|
98
|
+
infer_format_validation_for(property, opts.dup)
|
99
|
+
infer_uniqueness_validation_for(property, opts.dup)
|
100
|
+
infer_within_validation_for(property, opts.dup)
|
101
|
+
infer_numeric_validation_for(property, opts.dup)
|
102
|
+
end # auto_generate_validations
|
103
|
+
|
104
|
+
# Checks whether auto validations are currently
|
105
|
+
# disabled (see +disable_auto_validations+ method
|
106
|
+
# that takes a block)
|
107
|
+
#
|
108
|
+
# @return [TrueClass, FalseClass]
|
109
|
+
# true if auto validation is currently disabled
|
110
|
+
#
|
111
|
+
def disabled_auto_validations?
|
112
|
+
@disable_auto_validations || false
|
113
|
+
end
|
114
|
+
alias auto_validations_disabled? disabled_auto_validations?
|
86
115
|
|
87
|
-
|
88
|
-
|
116
|
+
|
117
|
+
# Checks whether or not property should be auto validated.
|
118
|
+
# It is the case for properties with :auto_validation option
|
119
|
+
# given and it's value evaluates to true
|
120
|
+
#
|
121
|
+
# @return [TrueClass, FalseClass]
|
122
|
+
# true for properties with :auto_validation option that has positive value
|
123
|
+
def skip_auto_validation_for?(property)
|
124
|
+
property.options.has_key?(:auto_validation) && !property.options[:auto_validation]
|
125
|
+
end
|
126
|
+
|
127
|
+
def infer_presence_validation_for(property, options)
|
128
|
+
unless allow_nil?(property)
|
89
129
|
# validates_present property.name, opts
|
90
|
-
validates_present property.name, options_with_message(
|
130
|
+
validates_present property.name, options_with_message(options, property, :presence)
|
91
131
|
end
|
132
|
+
end
|
92
133
|
|
93
|
-
|
94
|
-
if property.type
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
opts[:within] = len
|
99
|
-
else
|
100
|
-
opts[:maximum] = len
|
134
|
+
def infer_length_validation_for(property, options)
|
135
|
+
if [ String, DataMapper::Types::Text ].include?(property.type)
|
136
|
+
case length = property.options.fetch(:length, DataMapper::Property::DEFAULT_LENGTH)
|
137
|
+
when Range then options[:within] = length
|
138
|
+
else options[:maximum] = length
|
101
139
|
end
|
102
|
-
|
103
|
-
validates_length property.name, options_with_message(
|
140
|
+
|
141
|
+
validates_length property.name, options_with_message(options, property, :length)
|
104
142
|
end
|
143
|
+
end
|
105
144
|
|
106
|
-
|
145
|
+
def infer_format_validation_for(property, options)
|
107
146
|
if property.options.has_key?(:format)
|
108
|
-
|
109
|
-
|
110
|
-
validates_format property.name, options_with_message(opts, property, :format)
|
147
|
+
options[:with] = property.options[:format]
|
148
|
+
validates_format property.name, options_with_message(options, property, :format)
|
111
149
|
end
|
150
|
+
end
|
112
151
|
|
113
|
-
|
152
|
+
def infer_uniqueness_validation_for(property, options)
|
114
153
|
if property.options.has_key?(:unique)
|
115
154
|
value = property.options[:unique]
|
116
155
|
if value.is_a?(Array) || value.is_a?(Symbol)
|
117
|
-
# validates_is_unique property.name, :scope => Array(value)
|
118
156
|
validates_is_unique property.name, options_with_message({:scope => Array(value)}, property, :is_unique)
|
119
157
|
elsif value.is_a?(TrueClass)
|
120
|
-
# validates_is_unique property.name
|
121
158
|
validates_is_unique property.name, options_with_message({}, property, :is_unique)
|
122
159
|
end
|
123
160
|
end
|
161
|
+
end
|
124
162
|
|
125
|
-
|
126
|
-
if property.options.has_key?(:set)
|
127
|
-
|
128
|
-
|
163
|
+
def infer_within_validation_for(property, options)
|
164
|
+
validates_within property.name, options_with_message({:set => property.options[:set]}, property, :within) if property.options.has_key?(:set)
|
165
|
+
end
|
166
|
+
|
167
|
+
def infer_numeric_validation_for(property, options)
|
168
|
+
options[:gte] = property.min if property.min
|
169
|
+
options[:lte] = property.max if property.max
|
129
170
|
|
130
|
-
# numeric validator
|
131
171
|
if Integer == property.type
|
132
|
-
|
133
|
-
|
134
|
-
validates_is_number property.name, options_with_message(
|
172
|
+
options[:integer_only] = true
|
173
|
+
|
174
|
+
validates_is_number property.name, options_with_message(options, property, :is_number)
|
135
175
|
elsif BigDecimal == property.type || Float == property.type
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
validates_is_number property.name, options_with_message(
|
176
|
+
options[:precision] = property.precision
|
177
|
+
options[:scale] = property.scale
|
178
|
+
|
179
|
+
validates_is_number property.name, options_with_message(options, property, :is_number)
|
140
180
|
else
|
141
181
|
# We only need this in the case we don't already
|
142
182
|
# have a numeric validator, because otherwise
|
143
183
|
# it will cause duplicate validation errors
|
144
|
-
unless property.custom?
|
145
|
-
# validates_is_primitive property.name, opts
|
146
|
-
validates_is_primitive property.name, options_with_message(opts, property, :is_primitive)
|
147
|
-
end
|
184
|
+
validates_is_primitive property.name, options_with_message(options, property, :is_primitive) unless property.custom?
|
148
185
|
end
|
149
186
|
end
|
150
187
|
|
188
|
+
private
|
189
|
+
|
190
|
+
def allow_nil?(property)
|
191
|
+
property.nullable? || property.serial?
|
192
|
+
end
|
151
193
|
end # module AutoValidate
|
152
194
|
end # module Validate
|
153
195
|
end # module DataMapper
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module DataMapper
|
2
4
|
module Validate
|
3
5
|
|
@@ -6,23 +8,38 @@ module DataMapper
|
|
6
8
|
# @author Guy van den Berg
|
7
9
|
# @since 0.9
|
8
10
|
class ContextualValidators
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
#
|
14
|
+
# Delegators
|
15
|
+
#
|
16
|
+
|
17
|
+
def_delegators :@contexts, :empty?, :each
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
attr_reader :contexts
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@contexts = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# API
|
28
|
+
#
|
9
29
|
|
10
30
|
def dump
|
11
31
|
contexts.each_pair do |key, context|
|
12
32
|
puts "Key=#{key} Context: #{context}"
|
13
33
|
end
|
14
34
|
end
|
15
|
-
|
16
|
-
# Get a hash of named context validators for the resource
|
17
|
-
#
|
18
|
-
# @return <Hash> a hash of validators <GenericValidator>
|
19
|
-
def contexts
|
20
|
-
@contexts ||= {}
|
21
|
-
end
|
35
|
+
alias_method :inspect, :dump
|
22
36
|
|
23
37
|
# Return an array of validators for a named context
|
24
38
|
#
|
25
|
-
# @
|
39
|
+
# @param [String]
|
40
|
+
# Context name for which return validators
|
41
|
+
# @return [Array<DataMapper::Validate::GenericValidator>]
|
42
|
+
# An array of validators
|
26
43
|
def context(name)
|
27
44
|
contexts[name] ||= []
|
28
45
|
end
|
@@ -35,18 +52,24 @@ module DataMapper
|
|
35
52
|
|
36
53
|
# Execute all validators in the named context against the target
|
37
54
|
#
|
38
|
-
# @param
|
39
|
-
#
|
40
|
-
# @
|
55
|
+
# @param [Symbol]
|
56
|
+
# named_context the context we are validating against
|
57
|
+
# @param [Object]
|
58
|
+
# target the resource that we are validating
|
59
|
+
# @return [Boolean]
|
60
|
+
# true if all are valid, otherwise false
|
41
61
|
def execute(named_context, target)
|
42
|
-
raise(ArgumentError,
|
62
|
+
raise(ArgumentError, "validation context #{named_context} doesn't seem to be defined. Known contexts are #{contexts.keys.inspect}") if !named_context || (contexts.length > 0 && !contexts[named_context])
|
43
63
|
target.errors.clear!
|
44
64
|
result = true
|
45
|
-
|
46
|
-
|
65
|
+
# note that all? and any? stop iteration on first negative or positive result,
|
66
|
+
# so we really have to use each here to make sure all validators are
|
67
|
+
# executed
|
68
|
+
context(named_context).select { |validator| validator.execute?(target) }.each do |validator|
|
47
69
|
result = false unless validator.call(target)
|
48
70
|
end
|
49
71
|
|
72
|
+
|
50
73
|
result
|
51
74
|
end
|
52
75
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module DataMapper
|
2
4
|
module Validate
|
3
5
|
module Format
|
@@ -11,7 +13,7 @@ module DataMapper
|
|
11
13
|
|
12
14
|
Url = begin
|
13
15
|
# Regex from http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/
|
14
|
-
/(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})
|
16
|
+
/(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}((\:[0-9]{1,5})?\/?.*)?$)/ix
|
15
17
|
end
|
16
18
|
|
17
19
|
end # module Url
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Validate
|
3
|
+
|
4
|
+
# Module with validation context functionality.
|
5
|
+
#
|
6
|
+
# Contexts are implemented using a simple array based
|
7
|
+
# stack that is thread local. The default context can be
|
8
|
+
# altered by overwriting default_validation_context or
|
9
|
+
# will default to :default
|
10
|
+
#
|
11
|
+
module Context
|
12
|
+
|
13
|
+
# TODO: document
|
14
|
+
# @api private
|
15
|
+
def default_validation_context
|
16
|
+
current_validation_context || :default
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# Pushes given context on top of context stack and yields
|
22
|
+
# given block, then pops the stack. During block execution
|
23
|
+
# contexts previously pushed onto the stack have no effect.
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
def validation_context(context = default_validation_context)
|
27
|
+
validation_context_stack << context
|
28
|
+
begin
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
validation_context_stack.pop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Initializes (if necessary) and returns current scope stack
|
38
|
+
# @api private
|
39
|
+
def validation_context_stack
|
40
|
+
Thread.current[:dm_validations_context_stack] ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the current validation context or nil if none has been pushed
|
44
|
+
# @api private
|
45
|
+
def current_validation_context
|
46
|
+
validation_context_stack.last
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
include Context
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'extlib/dictionary'
|
2
|
+
|
1
3
|
module DataMapper
|
2
4
|
module Validate
|
3
5
|
|
@@ -10,27 +12,28 @@ module DataMapper
|
|
10
12
|
include Enumerable
|
11
13
|
|
12
14
|
@@default_error_messages = {
|
13
|
-
:absent
|
14
|
-
:inclusion
|
15
|
-
:invalid
|
16
|
-
:confirmation
|
17
|
-
:accepted
|
18
|
-
:nil
|
19
|
-
:blank
|
20
|
-
:length_between
|
21
|
-
:too_long
|
22
|
-
:too_short
|
23
|
-
:wrong_length
|
24
|
-
:taken
|
25
|
-
:not_a_number
|
26
|
-
:not_an_integer
|
27
|
-
:greater_than
|
28
|
-
:greater_than_or_equal_to =>
|
29
|
-
:equal_to
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
15
|
+
:absent => '%s must be absent',
|
16
|
+
:inclusion => '%s must be one of %s',
|
17
|
+
:invalid => '%s has an invalid format',
|
18
|
+
:confirmation => '%s does not match the confirmation',
|
19
|
+
:accepted => '%s is not accepted',
|
20
|
+
:nil => '%s must not be nil',
|
21
|
+
:blank => '%s must not be blank',
|
22
|
+
:length_between => '%s must be between %s and %s characters long',
|
23
|
+
:too_long => '%s must be at most %s characters long',
|
24
|
+
:too_short => '%s must be at least %s characters long',
|
25
|
+
:wrong_length => '%s must be %s characters long',
|
26
|
+
:taken => '%s is already taken',
|
27
|
+
:not_a_number => '%s must be a number',
|
28
|
+
:not_an_integer => '%s must be an integer',
|
29
|
+
:greater_than => '%s must be greater than %s',
|
30
|
+
:greater_than_or_equal_to => '%s must be greater than or equal to %s',
|
31
|
+
:equal_to => '%s must be equal to %s',
|
32
|
+
:not_equal_to => '%s must not be equal to %s',
|
33
|
+
:less_than => '%s must be less than %s',
|
34
|
+
:less_than_or_equal_to => '%s must be less than or equal to %s',
|
35
|
+
:value_between => '%s must be between %s and %s',
|
36
|
+
:primitive => '%s must be of type %s'
|
34
37
|
}
|
35
38
|
|
36
39
|
# Holds a hash with all the default error messages that can be replaced by your own copy or localizations.
|
@@ -41,6 +44,13 @@ module DataMapper
|
|
41
44
|
@@default_error_messages[key] % [field, *values].flatten
|
42
45
|
end
|
43
46
|
|
47
|
+
attr_reader :resource
|
48
|
+
|
49
|
+
def initialize(resource)
|
50
|
+
@resource = resource
|
51
|
+
@errors = Dictionary.new
|
52
|
+
end
|
53
|
+
|
44
54
|
# Clear existing validation errors.
|
45
55
|
def clear!
|
46
56
|
errors.clear
|
@@ -49,9 +59,21 @@ module DataMapper
|
|
49
59
|
# Add a validation error. Use the field_name :general if the errors does
|
50
60
|
# not apply to a specific field of the Resource.
|
51
61
|
#
|
52
|
-
# @param
|
53
|
-
# @param
|
62
|
+
# @param [Symbol] field_name the name of the field that caused the error
|
63
|
+
# @param [String] message the message to add
|
54
64
|
def add(field_name, message)
|
65
|
+
# see 6abe8fff in extlib, but don't enforce
|
66
|
+
# it unless Edge version is installed
|
67
|
+
if message.respond_to?(:try_call)
|
68
|
+
|
69
|
+
# DM resource
|
70
|
+
message = if resource.respond_to?(:model) && resource.model.respond_to?(:properties)
|
71
|
+
message.try_call(resource, resource.model.properties[field_name])
|
72
|
+
else
|
73
|
+
# pure Ruby object
|
74
|
+
message.try_call(resource)
|
75
|
+
end
|
76
|
+
end
|
55
77
|
(errors[field_name] ||= []) << message
|
56
78
|
end
|
57
79
|
|
@@ -64,10 +86,12 @@ module DataMapper
|
|
64
86
|
|
65
87
|
# Return validation errors for a particular field_name.
|
66
88
|
#
|
67
|
-
# @param
|
89
|
+
# @param [Symbol] field_name the name of the field you want an error for
|
90
|
+
# @return [Array<DataMapper::Validate::Error>]
|
91
|
+
# array of validation errors or empty array, if there are no errors on given field
|
68
92
|
def on(field_name)
|
69
93
|
errors_for_field = errors[field_name]
|
70
|
-
errors_for_field.blank? ? nil : errors_for_field
|
94
|
+
errors_for_field.blank? ? nil : errors_for_field.uniq
|
71
95
|
end
|
72
96
|
|
73
97
|
def each
|
@@ -78,7 +102,7 @@ module DataMapper
|
|
78
102
|
end
|
79
103
|
|
80
104
|
def empty?
|
81
|
-
|
105
|
+
@errors.empty?
|
82
106
|
end
|
83
107
|
|
84
108
|
def method_missing(meth, *args, &block)
|
@@ -87,7 +111,7 @@ module DataMapper
|
|
87
111
|
|
88
112
|
private
|
89
113
|
def errors
|
90
|
-
@errors
|
114
|
+
@errors
|
91
115
|
end
|
92
116
|
|
93
117
|
end # class ValidationErrors
|