sbf-dm-validations 1.3.0.beta
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.
- checksums.yaml +7 -0
- data/.gitignore +38 -0
- data/.rspec +1 -0
- data/.rubocop.yml +468 -0
- data/.travis.yml +51 -0
- data/Gemfile +60 -0
- data/LICENSE +21 -0
- data/README.rdoc +122 -0
- data/Rakefile +4 -0
- data/dm-validations.gemspec +20 -0
- data/lib/data_mapper/core.rb +1 -0
- data/lib/data_mapper/support/assertions.rb +1 -0
- data/lib/data_mapper/support/equalizer.rb +1 -0
- data/lib/data_mapper/support/ordered_set.rb +2 -0
- data/lib/data_mapper/validation/backward.rb +205 -0
- data/lib/data_mapper/validation/context.rb +57 -0
- data/lib/data_mapper/validation/contextual_rule_set.rb +210 -0
- data/lib/data_mapper/validation/exceptions.rb +7 -0
- data/lib/data_mapper/validation/inferred.rb +264 -0
- data/lib/data_mapper/validation/macros.rb +449 -0
- data/lib/data_mapper/validation/message_transformer.rb +111 -0
- data/lib/data_mapper/validation/model_extensions.rb +17 -0
- data/lib/data_mapper/validation/resource_extensions.rb +131 -0
- data/lib/data_mapper/validation/rule/absence.rb +31 -0
- data/lib/data_mapper/validation/rule/acceptance.rb +49 -0
- data/lib/data_mapper/validation/rule/block.rb +37 -0
- data/lib/data_mapper/validation/rule/confirmation.rb +47 -0
- data/lib/data_mapper/validation/rule/format/proc.rb +34 -0
- data/lib/data_mapper/validation/rule/format/regexp.rb +51 -0
- data/lib/data_mapper/validation/rule/format.rb +86 -0
- data/lib/data_mapper/validation/rule/formats/email.rb +54 -0
- data/lib/data_mapper/validation/rule/formats/url.rb +13 -0
- data/lib/data_mapper/validation/rule/length/equal.rb +48 -0
- data/lib/data_mapper/validation/rule/length/maximum.rb +50 -0
- data/lib/data_mapper/validation/rule/length/minimum.rb +50 -0
- data/lib/data_mapper/validation/rule/length/range.rb +50 -0
- data/lib/data_mapper/validation/rule/length.rb +96 -0
- data/lib/data_mapper/validation/rule/method.rb +42 -0
- data/lib/data_mapper/validation/rule/numericalness/equal.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/greater_than.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/greater_than_or_equal.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/integer.rb +41 -0
- data/lib/data_mapper/validation/rule/numericalness/less_than.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/less_than_or_equal.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/not_equal.rb +34 -0
- data/lib/data_mapper/validation/rule/numericalness/numeric.rb +68 -0
- data/lib/data_mapper/validation/rule/numericalness.rb +91 -0
- data/lib/data_mapper/validation/rule/presence.rb +52 -0
- data/lib/data_mapper/validation/rule/primitive_type.rb +32 -0
- data/lib/data_mapper/validation/rule/uniqueness.rb +64 -0
- data/lib/data_mapper/validation/rule/within/range/bounded.rb +29 -0
- data/lib/data_mapper/validation/rule/within/range/unbounded_begin.rb +29 -0
- data/lib/data_mapper/validation/rule/within/range/unbounded_end.rb +29 -0
- data/lib/data_mapper/validation/rule/within/range.rb +55 -0
- data/lib/data_mapper/validation/rule/within/set.rb +45 -0
- data/lib/data_mapper/validation/rule/within.rb +32 -0
- data/lib/data_mapper/validation/rule.rb +232 -0
- data/lib/data_mapper/validation/rule_set.rb +157 -0
- data/lib/data_mapper/validation/support/object.rb +19 -0
- data/lib/data_mapper/validation/support/ordered_hash.rb +434 -0
- data/lib/data_mapper/validation/version.rb +5 -0
- data/lib/data_mapper/validation/violation.rb +136 -0
- data/lib/data_mapper/validation/violation_set.rb +115 -0
- data/lib/data_mapper/validation.rb +105 -0
- data/lib/dm-validations.rb +24 -0
- data/spec/data_mapper/validation/resource_extensions/save_spec.rb +56 -0
- data/spec/data_mapper/validation/resource_extensions/validate_spec.rb +103 -0
- data/spec/fixtures/barcode.rb +40 -0
- data/spec/fixtures/basketball_court.rb +58 -0
- data/spec/fixtures/basketball_player.rb +34 -0
- data/spec/fixtures/beta_tester_account.rb +33 -0
- data/spec/fixtures/bill_of_landing.rb +47 -0
- data/spec/fixtures/boat_dock.rb +26 -0
- data/spec/fixtures/city.rb +24 -0
- data/spec/fixtures/company.rb +93 -0
- data/spec/fixtures/corporate_world.rb +39 -0
- data/spec/fixtures/country.rb +24 -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/integer_dumped_as_string_property.rb +24 -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/llama_spaceship.rb +15 -0
- data/spec/fixtures/mathematical_function.rb +34 -0
- data/spec/fixtures/memory_object.rb +35 -0
- data/spec/fixtures/mittelschnauzer.rb +39 -0
- data/spec/fixtures/motor_launch.rb +21 -0
- data/spec/fixtures/multibyte.rb +16 -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 +56 -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 +90 -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 +57 -0
- data/spec/integration/automatic_validation/disabling_inferred_validation_spec.rb +49 -0
- data/spec/integration/automatic_validation/inferred_boolean_properties_validation_spec.rb +100 -0
- data/spec/integration/automatic_validation/inferred_float_property_validation_spec.rb +45 -0
- data/spec/integration/automatic_validation/inferred_format_validation_spec.rb +35 -0
- data/spec/integration/automatic_validation/inferred_integer_properties_validation_spec.rb +70 -0
- data/spec/integration/automatic_validation/inferred_length_validation_spec.rb +142 -0
- data/spec/integration/automatic_validation/inferred_presence_validation_spec.rb +45 -0
- data/spec/integration/automatic_validation/inferred_primitive_validation_spec.rb +22 -0
- data/spec/integration/automatic_validation/inferred_uniqueness_validation_spec.rb +48 -0
- data/spec/integration/automatic_validation/inferred_within_validation_spec.rb +35 -0
- data/spec/integration/automatic_validation/spec_helper.rb +57 -0
- data/spec/integration/block_validator/spec_helper.rb +5 -0
- data/spec/integration/conditional_validation/if_condition_spec.rb +63 -0
- data/spec/integration/conditional_validation/spec_helper.rb +5 -0
- data/spec/integration/confirmation_validator/confirmation_validator_spec.rb +76 -0
- data/spec/integration/confirmation_validator/spec_helper.rb +5 -0
- data/spec/integration/datamapper_models/association_validation_spec.rb +29 -0
- data/spec/integration/datamapper_models/inheritance_spec.rb +82 -0
- data/spec/integration/dirty_attributes/dirty_attributes_spec.rb +13 -0
- data/spec/integration/duplicated_validations/duplicated_validations_spec.rb +24 -0
- data/spec/integration/duplicated_validations/spec_helper.rb +5 -0
- data/spec/integration/format_validator/email_format_validator_spec.rb +139 -0
- data/spec/integration/format_validator/format_validator_spec.rb +64 -0
- data/spec/integration/format_validator/regexp_validator_spec.rb +33 -0
- data/spec/integration/format_validator/spec_helper.rb +5 -0
- data/spec/integration/format_validator/url_format_validator_spec.rb +91 -0
- data/spec/integration/length_validator/default_value_spec.rb +14 -0
- data/spec/integration/length_validator/equality_spec.rb +83 -0
- data/spec/integration/length_validator/error_message_spec.rb +22 -0
- data/spec/integration/length_validator/maximum_spec.rb +47 -0
- data/spec/integration/length_validator/minimum_spec.rb +54 -0
- data/spec/integration/length_validator/range_spec.rb +87 -0
- data/spec/integration/length_validator/spec_helper.rb +7 -0
- data/spec/integration/method_validator/method_validator_spec.rb +243 -0
- data/spec/integration/method_validator/spec_helper.rb +5 -0
- data/spec/integration/numeric_validator/equality_with_float_type_spec.rb +65 -0
- data/spec/integration/numeric_validator/equality_with_integer_type_spec.rb +41 -0
- data/spec/integration/numeric_validator/float_type_spec.rb +90 -0
- data/spec/integration/numeric_validator/gt_with_float_type_spec.rb +37 -0
- data/spec/integration/numeric_validator/gte_with_float_type_spec.rb +36 -0
- data/spec/integration/numeric_validator/integer_only_true_spec.rb +91 -0
- data/spec/integration/numeric_validator/integer_type_spec.rb +86 -0
- data/spec/integration/numeric_validator/lt_with_float_type_spec.rb +37 -0
- data/spec/integration/numeric_validator/lte_with_float_type_spec.rb +37 -0
- data/spec/integration/numeric_validator/spec_helper.rb +5 -0
- data/spec/integration/primitive_validator/primitive_validator_spec.rb +112 -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 +69 -0
- data/spec/integration/required_field_validator/boolean_type_value_spec.rb +164 -0
- data/spec/integration/required_field_validator/date_type_value_spec.rb +127 -0
- data/spec/integration/required_field_validator/datetime_type_value_spec.rb +127 -0
- data/spec/integration/required_field_validator/float_type_value_spec.rb +131 -0
- data/spec/integration/required_field_validator/integer_type_value_spec.rb +99 -0
- data/spec/integration/required_field_validator/plain_old_ruby_object_spec.rb +35 -0
- data/spec/integration/required_field_validator/shared_examples.rb +27 -0
- data/spec/integration/required_field_validator/spec_helper.rb +7 -0
- data/spec/integration/required_field_validator/string_type_value_spec.rb +167 -0
- data/spec/integration/required_field_validator/text_type_value_spec.rb +49 -0
- data/spec/integration/shared/default_validation_context.rb +13 -0
- data/spec/integration/shared/valid_and_invalid_model.rb +35 -0
- data/spec/integration/uniqueness_validator/spec_helper.rb +5 -0
- data/spec/integration/uniqueness_validator/uniqueness_validator_spec.rb +116 -0
- data/spec/integration/within_validator/spec_helper.rb +5 -0
- data/spec/integration/within_validator/within_validator_spec.rb +168 -0
- data/spec/public/resource_spec.rb +113 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/unit/contextual_validators/emptiness_spec.rb +50 -0
- data/spec/unit/contextual_validators/execution_spec.rb +48 -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/generic_validator/optional_spec.rb +54 -0
- data/spec/unit/validators/within_validator_spec.rb +23 -0
- data/spec/unit/violation_set/adding_spec.rb +54 -0
- data/spec/unit/violation_set/emptiness_spec.rb +38 -0
- data/spec/unit/violation_set/enumerable_spec.rb +32 -0
- data/spec/unit/violation_set/reading_spec.rb +35 -0
- data/spec/unit/violation_set/respond_to_spec.rb +15 -0
- data/tasks/spec.rake +21 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +245 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Validation
|
|
3
|
+
# Transforms Violations to error message strings.
|
|
4
|
+
#
|
|
5
|
+
# @abstract
|
|
6
|
+
# Subclass and override {#transform} to implement a custom message
|
|
7
|
+
# transformer. Use {Violation.message_transformer=} to set a new
|
|
8
|
+
# message transformer or pass the transformer to {Violation#message}.
|
|
9
|
+
class MessageTransformer
|
|
10
|
+
|
|
11
|
+
# Transforms the specified Violation to an error message string.
|
|
12
|
+
#
|
|
13
|
+
# @param [Violation] violation
|
|
14
|
+
# The Violation to transform.
|
|
15
|
+
#
|
|
16
|
+
# @return [String]
|
|
17
|
+
# The transformed message.
|
|
18
|
+
#
|
|
19
|
+
# @raise [ArgumentError]
|
|
20
|
+
# +violation+ is +nil+.
|
|
21
|
+
def transform(violation)
|
|
22
|
+
raise NotImplementedError, "#{self.class}#transform must be implemented"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Default < self
|
|
27
|
+
@error_messages = {
|
|
28
|
+
:absent => '%s must be absent',
|
|
29
|
+
:inclusion => '%s must be one of %s',
|
|
30
|
+
:invalid => '%s has an invalid format',
|
|
31
|
+
:confirmation => '%s does not match the confirmation',
|
|
32
|
+
:accepted => '%s is not accepted',
|
|
33
|
+
:nil => '%s must not be nil',
|
|
34
|
+
:blank => '%s must not be blank',
|
|
35
|
+
:length_between => '%s must be between %s and %s characters long',
|
|
36
|
+
:too_long => '%s must be at most %s characters long',
|
|
37
|
+
:too_short => '%s must be at least %s characters long',
|
|
38
|
+
:wrong_length => '%s must be %s characters long',
|
|
39
|
+
:taken => '%s is already taken',
|
|
40
|
+
:not_a_number => '%s must be a number',
|
|
41
|
+
:not_an_integer => '%s must be an integer',
|
|
42
|
+
:greater_than => '%s must be greater than %s',
|
|
43
|
+
:greater_than_or_equal_to => '%s must be greater than or equal to %s',
|
|
44
|
+
:equal_to => '%s must be equal to %s',
|
|
45
|
+
:not_equal_to => '%s must not be equal to %s',
|
|
46
|
+
:less_than => '%s must be less than %s',
|
|
47
|
+
:less_than_or_equal_to => '%s must be less than or equal to %s',
|
|
48
|
+
:value_between => '%s must be between %s and %s',
|
|
49
|
+
:primitive => '%s must be of type %s'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
# Gets the hash of error messages used to transform violations.
|
|
54
|
+
#
|
|
55
|
+
# @return [Hash{Symbol=>String}]
|
|
56
|
+
attr_reader :error_messages
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Merges the specified +error_messages+ hash into the internal hash of
|
|
60
|
+
# error messages.
|
|
61
|
+
#
|
|
62
|
+
# @param [Hash{Symbol=>String}] error_messages
|
|
63
|
+
# The error messages to be merged.
|
|
64
|
+
def self.error_messages=(error_messages)
|
|
65
|
+
unless error_messages.is_a?(Hash)
|
|
66
|
+
raise ArgumentError, "+error_messages+ must be a hash"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
self.error_messages.merge!(error_messages)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.error_message(violation_type, attribute_name, violation_values)
|
|
73
|
+
if message = self.error_messages[violation_type]
|
|
74
|
+
attribute_name = DataMapper::Inflector.humanize(attribute_name)
|
|
75
|
+
message % [attribute_name, *violation_values].flatten
|
|
76
|
+
else
|
|
77
|
+
violation_type.to_s
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def transform(violation)
|
|
82
|
+
raise ArgumentError, "+violation+ must be specified" if violation.nil?
|
|
83
|
+
|
|
84
|
+
attribute_name = violation.attribute_name
|
|
85
|
+
|
|
86
|
+
self.class.error_message(violation.type, attribute_name, violation.values)
|
|
87
|
+
end
|
|
88
|
+
end # class Default
|
|
89
|
+
|
|
90
|
+
class DefaultI18n < self
|
|
91
|
+
def transform(violation)
|
|
92
|
+
raise ArgumentError, "+violation+ must be specified" if violation.nil?
|
|
93
|
+
|
|
94
|
+
resource = violation.resource
|
|
95
|
+
model_name = resource.model.model_name
|
|
96
|
+
attribute_name = violation.attribute_name
|
|
97
|
+
|
|
98
|
+
options = {
|
|
99
|
+
:model => ::I18n.translate("models.#{model_name}"),
|
|
100
|
+
:attribute => ::I18n.translate("attributes.#{model_name}.#{attribute_name}"),
|
|
101
|
+
:value => resource.validation_property_value(attribute_name)
|
|
102
|
+
}.merge(violation.info)
|
|
103
|
+
|
|
104
|
+
::I18n.translate("errors.#{violation.type}", options)
|
|
105
|
+
end
|
|
106
|
+
end # class I18n
|
|
107
|
+
|
|
108
|
+
end # class MessageTransformer
|
|
109
|
+
|
|
110
|
+
end # module Validation
|
|
111
|
+
end # module DataMapper
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Validation
|
|
3
|
+
module ModelExtensions
|
|
4
|
+
|
|
5
|
+
# @api public
|
|
6
|
+
def create(attributes = {}, *args)
|
|
7
|
+
resource = new(attributes)
|
|
8
|
+
resource.save(*args)
|
|
9
|
+
resource
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end # module ModelExtensions
|
|
13
|
+
end # module Validation
|
|
14
|
+
|
|
15
|
+
Model.append_extensions Validation::ModelExtensions
|
|
16
|
+
|
|
17
|
+
end # module DataMapper
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require 'data_mapper/core'
|
|
2
|
+
require 'data_mapper/validation'
|
|
3
|
+
require 'data_mapper/validation/context'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
|
|
8
|
+
module ResourceExtensions
|
|
9
|
+
|
|
10
|
+
# TODO: contemplate reworking dm-core to allow hooks to be fired even if
|
|
11
|
+
# the hooked event does not transpire (eg., `before :save` when clean)
|
|
12
|
+
# def self.included(model)
|
|
13
|
+
# model.before :save, :validate_or_halt
|
|
14
|
+
# end
|
|
15
|
+
|
|
16
|
+
# Ensures the object is valid for the context provided, and otherwise
|
|
17
|
+
# throws :halt and returns false.
|
|
18
|
+
#
|
|
19
|
+
# @param [Symbol] context
|
|
20
|
+
# context for which to validate the Resource, defaulting to
|
|
21
|
+
# #default_validation_context
|
|
22
|
+
#
|
|
23
|
+
# @return [Boolean]
|
|
24
|
+
# whether the Resource was persisted successfully
|
|
25
|
+
#
|
|
26
|
+
# TODO: fix this to not change the method signature of #save
|
|
27
|
+
# TODO: add support for skipping validations by passing nil
|
|
28
|
+
#
|
|
29
|
+
# @api public
|
|
30
|
+
def save(context_name = default_validation_context)
|
|
31
|
+
validation_rules.assert_valid_context(context_name)
|
|
32
|
+
|
|
33
|
+
Context.in_context(context_name) { super() }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
def save_self(*)
|
|
38
|
+
return super unless dirty_self? || new?
|
|
39
|
+
if Context.any? && !valid?(validation_rules.current_context)
|
|
40
|
+
false
|
|
41
|
+
else
|
|
42
|
+
super
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Ensures the object is valid for the context provided, and otherwise
|
|
47
|
+
# throws :halt and returns false.
|
|
48
|
+
#
|
|
49
|
+
# @param [Hash] attributes
|
|
50
|
+
# attribute names and values which will be set on this Resource
|
|
51
|
+
# @param [Symbol] context
|
|
52
|
+
# context for which to validate the Resource, defaulting to
|
|
53
|
+
# #default_validation_context
|
|
54
|
+
#
|
|
55
|
+
# @return [Boolean]
|
|
56
|
+
# whether the Resource attributes were set and persisted successfully
|
|
57
|
+
#
|
|
58
|
+
# TODO: fix this to not change the method signature of #update
|
|
59
|
+
#
|
|
60
|
+
# @api public
|
|
61
|
+
def update(attributes = {}, context_name = default_validation_context)
|
|
62
|
+
validation_rules.assert_valid_context(context_name)
|
|
63
|
+
|
|
64
|
+
Context.in_context(context_name) { super(attributes) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @api public
|
|
68
|
+
def validate(context_name = default_validation_context)
|
|
69
|
+
super
|
|
70
|
+
#validate_parents # if model.validation_rules.validate_parents?
|
|
71
|
+
#validate_children # if model.validation_rules.validate_children?
|
|
72
|
+
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# @api private
|
|
79
|
+
def validate_parents
|
|
80
|
+
parent_relationships.each do |relationship|
|
|
81
|
+
next unless relationship.loaded?(self)
|
|
82
|
+
validate_parent_relationship(relationship)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @api private
|
|
87
|
+
def validate_children
|
|
88
|
+
child_relationships.each do |relationship|
|
|
89
|
+
next unless relationship.loaded?(self)
|
|
90
|
+
validate_child_relationship(relationship)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @api private
|
|
95
|
+
def validate_parent_relationship(relationship)
|
|
96
|
+
relationship_name = relationship.name
|
|
97
|
+
parent_model = relationship.target_model
|
|
98
|
+
context_name = parent_model.validation_rules.current_context
|
|
99
|
+
parent_resource = relationship.get(self)
|
|
100
|
+
|
|
101
|
+
parent_violations = parent_resource.validation_violations(context_name)
|
|
102
|
+
parent_violations.each { |v| errors[relationship_name] << v }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @api private
|
|
106
|
+
def validate_child_relationship(relationship)
|
|
107
|
+
relationship_name = relationship.name
|
|
108
|
+
child_model = relationship.target_model
|
|
109
|
+
context_name = child_model.validation_rules.current_context
|
|
110
|
+
child_collection = relationship.get_collection(self)
|
|
111
|
+
|
|
112
|
+
child_collection.each do |child_resource|
|
|
113
|
+
child_violations = child_resource.validation_violations(context_name)
|
|
114
|
+
child_violations.each { |v| errors[relationship_name] << v }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @see note at self.included, above
|
|
119
|
+
#
|
|
120
|
+
# @api private
|
|
121
|
+
# def validate_or_halt
|
|
122
|
+
# throw :halt if Context.any? && !valid?(validation_rules.current_context)
|
|
123
|
+
# end
|
|
124
|
+
|
|
125
|
+
end # module Resource
|
|
126
|
+
end # module Validation
|
|
127
|
+
|
|
128
|
+
Model.append_inclusions Validation
|
|
129
|
+
Model.append_inclusions Validation::ResourceExtensions
|
|
130
|
+
|
|
131
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
|
|
9
|
+
class Absence < Rule
|
|
10
|
+
|
|
11
|
+
def initialize(attribute_name, options = {})
|
|
12
|
+
super
|
|
13
|
+
|
|
14
|
+
@allow_nil = false
|
|
15
|
+
@allow_blank = false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def valid?(resource)
|
|
19
|
+
value = resource.validation_property_value(attribute_name)
|
|
20
|
+
DataMapper::Ext.blank?(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def violation_type(resource)
|
|
24
|
+
:absent
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end # class Absence
|
|
28
|
+
|
|
29
|
+
end # class Rule
|
|
30
|
+
end # module Validation
|
|
31
|
+
end # module DataMapper
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
|
|
9
|
+
# TODO: update this to inherit from Rule::Within::Set
|
|
10
|
+
class Acceptance < Rule
|
|
11
|
+
|
|
12
|
+
EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :accept
|
|
13
|
+
|
|
14
|
+
equalize *EQUALIZE_ON
|
|
15
|
+
|
|
16
|
+
DEFAULT_ACCEPTED_VALUES = [ '1', 1, 'true', true, 't' ]
|
|
17
|
+
|
|
18
|
+
attr_reader :accept
|
|
19
|
+
|
|
20
|
+
def initialize(attribute_name, options = {})
|
|
21
|
+
super
|
|
22
|
+
|
|
23
|
+
@accept = Array(options.fetch(:accept, DEFAULT_ACCEPTED_VALUES))
|
|
24
|
+
|
|
25
|
+
allow_nil! unless defined?(@allow_nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def valid?(resource)
|
|
29
|
+
value = resource.validation_property_value(attribute_name)
|
|
30
|
+
return true if exempt_value?(value)
|
|
31
|
+
accept.include?(value)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def violation_type(resource)
|
|
35
|
+
:accepted
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# TODO: isn't this superfluous considering Rule#optional?
|
|
41
|
+
def exempt_value?(value)
|
|
42
|
+
allow_nil? && value.nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end # class Acceptance
|
|
46
|
+
|
|
47
|
+
end # class Rule
|
|
48
|
+
end # module Validation
|
|
49
|
+
end # module DataMapper
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
|
|
9
|
+
class Block < Rule
|
|
10
|
+
|
|
11
|
+
attr_reader :block
|
|
12
|
+
|
|
13
|
+
def initialize(attribute_name, options, &block)
|
|
14
|
+
unless block_given?
|
|
15
|
+
raise ArgumentError, 'cannot initialize a Block validator without a block'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
super
|
|
19
|
+
|
|
20
|
+
@block = block
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate(resource)
|
|
24
|
+
result, error_message = resource.instance_eval(&self.block)
|
|
25
|
+
|
|
26
|
+
if result
|
|
27
|
+
nil
|
|
28
|
+
else
|
|
29
|
+
Violation.new(resource, error_message, self)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end # class Block
|
|
34
|
+
|
|
35
|
+
end # class Rule
|
|
36
|
+
end # module Validation
|
|
37
|
+
end # module DataMapper
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
|
|
9
|
+
class Confirmation < Rule
|
|
10
|
+
|
|
11
|
+
EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :confirmation_attribute
|
|
12
|
+
|
|
13
|
+
attr_reader :confirmation_attribute
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def initialize(attribute_name, options = {})
|
|
17
|
+
super
|
|
18
|
+
|
|
19
|
+
@confirm_attribute_name = options.fetch(:confirm) do
|
|
20
|
+
:"#{attribute_name}_confirmation"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
allow_nil! unless defined?(@allow_nil)
|
|
24
|
+
allow_blank! unless defined?(@allow_blank)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def valid?(resource)
|
|
28
|
+
value = resource.validation_property_value(attribute_name)
|
|
29
|
+
return true if optional?(value)
|
|
30
|
+
|
|
31
|
+
if resource.model.properties.named?(attribute_name)
|
|
32
|
+
return true unless resource.attribute_dirty?(attribute_name)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
confirm_value = resource.instance_variable_get("@#{@confirm_attribute_name}")
|
|
36
|
+
value == confirm_value
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def violation_type(resource)
|
|
40
|
+
:confirmation
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end # class Confirmation
|
|
44
|
+
|
|
45
|
+
end # class Rule
|
|
46
|
+
end # module Validation
|
|
47
|
+
end # module DataMapper
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule/format'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
module Format
|
|
9
|
+
|
|
10
|
+
class Proc < Rule
|
|
11
|
+
|
|
12
|
+
include Format
|
|
13
|
+
|
|
14
|
+
EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :format
|
|
15
|
+
|
|
16
|
+
equalize *EQUALIZE_ON
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def valid?(resource)
|
|
20
|
+
value = resource.validation_property_value(attribute_name)
|
|
21
|
+
return true if optional?(value)
|
|
22
|
+
|
|
23
|
+
self.format.call(value)
|
|
24
|
+
# rescue ::Encoding::CompatibilityError
|
|
25
|
+
# # This is to work around a bug in jruby - see formats/email.rb
|
|
26
|
+
# false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end # class Proc
|
|
30
|
+
|
|
31
|
+
end # module Format
|
|
32
|
+
end # class Rule
|
|
33
|
+
end # module Validation
|
|
34
|
+
end # module DataMapper
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule/format'
|
|
4
|
+
|
|
5
|
+
module DataMapper
|
|
6
|
+
module Validation
|
|
7
|
+
class Rule
|
|
8
|
+
module Format
|
|
9
|
+
|
|
10
|
+
class Regexp < Rule
|
|
11
|
+
|
|
12
|
+
include Format
|
|
13
|
+
|
|
14
|
+
EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :format << :format_name
|
|
15
|
+
|
|
16
|
+
equalize *EQUALIZE_ON
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
attr_reader :format_name
|
|
20
|
+
|
|
21
|
+
def initialize(attribute_name, options = {})
|
|
22
|
+
super
|
|
23
|
+
|
|
24
|
+
@format_name = options.fetch(:format_name, nil)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def valid?(resource)
|
|
28
|
+
value = resource.validation_property_value(attribute_name)
|
|
29
|
+
return true if optional?(value)
|
|
30
|
+
|
|
31
|
+
value ? value.to_s =~ self.format : false
|
|
32
|
+
rescue ::Encoding::CompatibilityError
|
|
33
|
+
# This is to work around a bug in jruby - see formats/email.rb
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# TODO: integrate format into error message key?
|
|
38
|
+
# def error_message_args
|
|
39
|
+
# if format_name.is_a?(Symbol)
|
|
40
|
+
# [ :"invalid_#{format_name}", attribute_name ]
|
|
41
|
+
# else
|
|
42
|
+
# [ :invalid, attribute_name ]
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
|
|
46
|
+
end # class Regexp
|
|
47
|
+
|
|
48
|
+
end # module Format
|
|
49
|
+
end # class Rule
|
|
50
|
+
end # module Validation
|
|
51
|
+
end # module DataMapper
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'data_mapper/validation/rule'
|
|
4
|
+
|
|
5
|
+
require 'data_mapper/validation/rule/formats/email'
|
|
6
|
+
require 'data_mapper/validation/rule/formats/url'
|
|
7
|
+
|
|
8
|
+
module DataMapper
|
|
9
|
+
module Validation
|
|
10
|
+
class UnknownValidationFormat < ::ArgumentError; end
|
|
11
|
+
|
|
12
|
+
class Rule
|
|
13
|
+
|
|
14
|
+
module Format
|
|
15
|
+
|
|
16
|
+
FORMATS = {
|
|
17
|
+
:email_address => Formats::EmailAddress,
|
|
18
|
+
:url => Formats::Url
|
|
19
|
+
}
|
|
20
|
+
# TODO: evaluate re-implementing custom error messages per format type
|
|
21
|
+
# previously these strings were wrapped in lambdas, which were, at one
|
|
22
|
+
# point, invoked with #try_call with the humanized attribute name and value
|
|
23
|
+
FORMAT_MESSAGES = {
|
|
24
|
+
:email_address => '%s is not a valid email address',
|
|
25
|
+
:url => '%s is not a valid URL',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def self.rules_for(attribute_name, options)
|
|
30
|
+
Array(new(attribute_name, options))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @raise [UnknownValidationFormat]
|
|
34
|
+
# if the :as (or :with) option is a Symbol that is not a key in FORMATS,
|
|
35
|
+
# or if the provided format is not a Regexp, Symbol or Proc
|
|
36
|
+
def self.new(attribute_name, options)
|
|
37
|
+
format = options.delete(:as) || options.delete(:with)
|
|
38
|
+
|
|
39
|
+
case format
|
|
40
|
+
when Symbol
|
|
41
|
+
regexp = FORMATS.fetch(format) do
|
|
42
|
+
raise UnknownValidationFormat, "No such predefined format '#{format}'"
|
|
43
|
+
end
|
|
44
|
+
self::Regexp.new(attribute_name, options.merge(:format => regexp, :format_name => format))
|
|
45
|
+
when ::Regexp
|
|
46
|
+
self::Regexp.new(attribute_name, options.merge(:format => format))
|
|
47
|
+
when ::Proc
|
|
48
|
+
self::Proc.new(attribute_name, options.merge(:format => format))
|
|
49
|
+
else
|
|
50
|
+
raise UnknownValidationFormat, "Expected a Regexp, Symbol, or Proc format. Got: #{format.inspect}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
attr_reader :format
|
|
56
|
+
|
|
57
|
+
def initialize(attribute_name, options)
|
|
58
|
+
super
|
|
59
|
+
|
|
60
|
+
@format = options.fetch(:format)
|
|
61
|
+
|
|
62
|
+
allow_nil! unless defined?(@allow_nil)
|
|
63
|
+
allow_blank! unless defined?(@allow_blank)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def violation_type(resource)
|
|
67
|
+
:invalid
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# TODO: integrate format into error message key?
|
|
71
|
+
# def error_message_args
|
|
72
|
+
# if format.is_a?(Symbol)
|
|
73
|
+
# [ :"invalid_#{format}", attribute_name ]
|
|
74
|
+
# else
|
|
75
|
+
# [ :invalid, attribute_name ]
|
|
76
|
+
# end
|
|
77
|
+
# end
|
|
78
|
+
|
|
79
|
+
end # class Format
|
|
80
|
+
|
|
81
|
+
end # class Rule
|
|
82
|
+
end # module Validation
|
|
83
|
+
end # module DataMapper
|
|
84
|
+
|
|
85
|
+
require 'data_mapper/validation/rule/format/proc'
|
|
86
|
+
require 'data_mapper/validation/rule/format/regexp'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module DataMapper
|
|
4
|
+
module Validation
|
|
5
|
+
class Rule
|
|
6
|
+
module Formats
|
|
7
|
+
|
|
8
|
+
# Almost RFC2822 (No attribution reference available).
|
|
9
|
+
#
|
|
10
|
+
# This differs in that it does not allow local domains (test@localhost).
|
|
11
|
+
# 99% of the time you do not want to allow these email addresses
|
|
12
|
+
# in a public web application.
|
|
13
|
+
EmailAddress = begin
|
|
14
|
+
if (RUBY_VERSION == '1.9.2' && RUBY_ENGINE == 'jruby' && JRUBY_VERSION <= '1.6.3') || RUBY_VERSION == '1.9.3'
|
|
15
|
+
# There is an obscure bug in jruby 1.6 that prevents matching
|
|
16
|
+
# on unicode properties here. Remove this logic branch once
|
|
17
|
+
# a stable jruby release fixes this.
|
|
18
|
+
#
|
|
19
|
+
# http://jira.codehaus.org/browse/JRUBY-5622
|
|
20
|
+
#
|
|
21
|
+
# There is a similar bug in preview releases of 1.9.3
|
|
22
|
+
#
|
|
23
|
+
# http://redmine.ruby-lang.org/issues/5126
|
|
24
|
+
letter = 'a-zA-Z'
|
|
25
|
+
else
|
|
26
|
+
letter = 'a-zA-Z\p{L}' # Changed from RFC2822 to include unicode chars
|
|
27
|
+
end
|
|
28
|
+
digit = '0-9'
|
|
29
|
+
atext = "[#{letter}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]"
|
|
30
|
+
dot_atom_text = "#{atext}+([.]#{atext}*)+"
|
|
31
|
+
dot_atom = dot_atom_text
|
|
32
|
+
no_ws_ctl = '\x01-\x08\x11\x12\x14-\x1f\x7f'
|
|
33
|
+
qtext = "[^#{no_ws_ctl}\\x0d\\x22\\x5c]" # Non-whitespace, non-control character except for \ and "
|
|
34
|
+
text = '[\x01-\x09\x11\x12\x14-\x7f]'
|
|
35
|
+
quoted_pair = "(\\x5c#{text})"
|
|
36
|
+
qcontent = "(?:#{qtext}|#{quoted_pair})"
|
|
37
|
+
quoted_string = "[\"]#{qcontent}+[\"]"
|
|
38
|
+
atom = "#{atext}+"
|
|
39
|
+
word = "(?:#{atom}|#{quoted_string})"
|
|
40
|
+
obs_local_part = "#{word}([.]#{word})*"
|
|
41
|
+
local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})"
|
|
42
|
+
dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]"
|
|
43
|
+
dcontent = "(?:#{dtext}|#{quoted_pair})"
|
|
44
|
+
domain_literal = "\\[#{dcontent}+\\]"
|
|
45
|
+
obs_domain = "#{atom}([.]#{atom})+"
|
|
46
|
+
domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})"
|
|
47
|
+
addr_spec = "#{local_part}\@#{domain}"
|
|
48
|
+
pattern = /\A#{addr_spec}\z/u
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end # module Formats
|
|
52
|
+
end # class Rule
|
|
53
|
+
end # module Validation
|
|
54
|
+
end # module DataMapper
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module DataMapper
|
|
4
|
+
module Validation
|
|
5
|
+
class Rule
|
|
6
|
+
module Formats
|
|
7
|
+
|
|
8
|
+
Url = %r{\Ahttps?://[a-z\d](?:[-.]?[a-z\d])*\.[a-z]{2,6}(?::\d{1,5})?/?.*\z}ix.freeze
|
|
9
|
+
|
|
10
|
+
end # module Formats
|
|
11
|
+
end # class Rule
|
|
12
|
+
end # module Validation
|
|
13
|
+
end # module DataMapper
|