sbf-dm-validations 1.3.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- 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
|