ardm-validations 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +51 -0
  5. data/LICENSE +21 -0
  6. data/README.rdoc +122 -0
  7. data/Rakefile +4 -0
  8. data/ardm-validations.gemspec +28 -0
  9. data/lib/ardm-validations.rb +1 -0
  10. data/lib/dm-validations.rb +169 -0
  11. data/lib/dm-validations/auto_validate.rb +252 -0
  12. data/lib/dm-validations/context.rb +66 -0
  13. data/lib/dm-validations/contextual_validators.rb +220 -0
  14. data/lib/dm-validations/exceptions.rb +5 -0
  15. data/lib/dm-validations/formats/email.rb +65 -0
  16. data/lib/dm-validations/formats/url.rb +27 -0
  17. data/lib/dm-validations/support/object.rb +18 -0
  18. data/lib/dm-validations/support/ordered_hash.rb +434 -0
  19. data/lib/dm-validations/validation_errors.rb +137 -0
  20. data/lib/dm-validations/validators/absent_field_validator.rb +58 -0
  21. data/lib/dm-validations/validators/acceptance_validator.rb +79 -0
  22. data/lib/dm-validations/validators/block_validator.rb +61 -0
  23. data/lib/dm-validations/validators/confirmation_validator.rb +92 -0
  24. data/lib/dm-validations/validators/format_validator.rb +124 -0
  25. data/lib/dm-validations/validators/generic_validator.rb +184 -0
  26. data/lib/dm-validations/validators/length_validator.rb +249 -0
  27. data/lib/dm-validations/validators/method_validator.rb +64 -0
  28. data/lib/dm-validations/validators/numeric_validator.rb +182 -0
  29. data/lib/dm-validations/validators/primitive_validator.rb +58 -0
  30. data/lib/dm-validations/validators/required_field_validator.rb +83 -0
  31. data/lib/dm-validations/validators/uniqueness_validator.rb +67 -0
  32. data/lib/dm-validations/validators/within_validator.rb +74 -0
  33. data/lib/dm-validations/version.rb +5 -0
  34. data/spec/fixtures/barcode.rb +40 -0
  35. data/spec/fixtures/basketball_court.rb +58 -0
  36. data/spec/fixtures/basketball_player.rb +34 -0
  37. data/spec/fixtures/beta_tester_account.rb +33 -0
  38. data/spec/fixtures/bill_of_landing.rb +47 -0
  39. data/spec/fixtures/boat_dock.rb +26 -0
  40. data/spec/fixtures/city.rb +24 -0
  41. data/spec/fixtures/company.rb +93 -0
  42. data/spec/fixtures/corporate_world.rb +39 -0
  43. data/spec/fixtures/country.rb +24 -0
  44. data/spec/fixtures/ethernet_frame.rb +56 -0
  45. data/spec/fixtures/event.rb +44 -0
  46. data/spec/fixtures/g3_concert.rb +57 -0
  47. data/spec/fixtures/jabberwock.rb +27 -0
  48. data/spec/fixtures/kayak.rb +28 -0
  49. data/spec/fixtures/lernean_hydra.rb +39 -0
  50. data/spec/fixtures/llama_spaceship.rb +15 -0
  51. data/spec/fixtures/mathematical_function.rb +34 -0
  52. data/spec/fixtures/memory_object.rb +30 -0
  53. data/spec/fixtures/mittelschnauzer.rb +39 -0
  54. data/spec/fixtures/motor_launch.rb +21 -0
  55. data/spec/fixtures/multibyte.rb +16 -0
  56. data/spec/fixtures/page.rb +32 -0
  57. data/spec/fixtures/phone_number.rb +28 -0
  58. data/spec/fixtures/pirogue.rb +28 -0
  59. data/spec/fixtures/programming_language.rb +83 -0
  60. data/spec/fixtures/reservation.rb +38 -0
  61. data/spec/fixtures/scm_operation.rb +56 -0
  62. data/spec/fixtures/sms_message.rb +22 -0
  63. data/spec/fixtures/udp_packet.rb +49 -0
  64. data/spec/integration/absent_field_validator/absent_field_validator_spec.rb +90 -0
  65. data/spec/integration/absent_field_validator/spec_helper.rb +7 -0
  66. data/spec/integration/acceptance_validator/acceptance_validator_spec.rb +196 -0
  67. data/spec/integration/acceptance_validator/spec_helper.rb +7 -0
  68. data/spec/integration/automatic_validation/custom_messages_for_inferred_validation_spec.rb +57 -0
  69. data/spec/integration/automatic_validation/disabling_inferred_validation_spec.rb +49 -0
  70. data/spec/integration/automatic_validation/inferred_boolean_properties_validation_spec.rb +100 -0
  71. data/spec/integration/automatic_validation/inferred_float_property_validation_spec.rb +45 -0
  72. data/spec/integration/automatic_validation/inferred_format_validation_spec.rb +35 -0
  73. data/spec/integration/automatic_validation/inferred_integer_properties_validation_spec.rb +70 -0
  74. data/spec/integration/automatic_validation/inferred_length_validation_spec.rb +142 -0
  75. data/spec/integration/automatic_validation/inferred_presence_validation_spec.rb +45 -0
  76. data/spec/integration/automatic_validation/inferred_primitive_validation_spec.rb +22 -0
  77. data/spec/integration/automatic_validation/inferred_uniqueness_validation_spec.rb +52 -0
  78. data/spec/integration/automatic_validation/inferred_within_validation_spec.rb +39 -0
  79. data/spec/integration/automatic_validation/spec_helper.rb +57 -0
  80. data/spec/integration/block_validator/block_validator_spec.rb +32 -0
  81. data/spec/integration/block_validator/spec_helper.rb +5 -0
  82. data/spec/integration/conditional_validation/if_condition_spec.rb +63 -0
  83. data/spec/integration/conditional_validation/spec_helper.rb +5 -0
  84. data/spec/integration/confirmation_validator/confirmation_validator_spec.rb +76 -0
  85. data/spec/integration/confirmation_validator/spec_helper.rb +5 -0
  86. data/spec/integration/datamapper_models/association_validation_spec.rb +29 -0
  87. data/spec/integration/datamapper_models/inheritance_spec.rb +82 -0
  88. data/spec/integration/dirty_attributes/dirty_attributes_spec.rb +13 -0
  89. data/spec/integration/duplicated_validations/duplicated_validations_spec.rb +24 -0
  90. data/spec/integration/duplicated_validations/spec_helper.rb +5 -0
  91. data/spec/integration/format_validator/email_format_validator_spec.rb +139 -0
  92. data/spec/integration/format_validator/format_validator_spec.rb +64 -0
  93. data/spec/integration/format_validator/regexp_validator_spec.rb +33 -0
  94. data/spec/integration/format_validator/spec_helper.rb +5 -0
  95. data/spec/integration/format_validator/url_format_validator_spec.rb +93 -0
  96. data/spec/integration/length_validator/default_value_spec.rb +14 -0
  97. data/spec/integration/length_validator/equality_spec.rb +87 -0
  98. data/spec/integration/length_validator/error_message_spec.rb +22 -0
  99. data/spec/integration/length_validator/maximum_spec.rb +49 -0
  100. data/spec/integration/length_validator/minimum_spec.rb +54 -0
  101. data/spec/integration/length_validator/range_spec.rb +87 -0
  102. data/spec/integration/length_validator/spec_helper.rb +7 -0
  103. data/spec/integration/method_validator/method_validator_spec.rb +241 -0
  104. data/spec/integration/method_validator/spec_helper.rb +5 -0
  105. data/spec/integration/numeric_validator/equality_with_float_type_spec.rb +65 -0
  106. data/spec/integration/numeric_validator/equality_with_integer_type_spec.rb +41 -0
  107. data/spec/integration/numeric_validator/float_type_spec.rb +90 -0
  108. data/spec/integration/numeric_validator/gt_with_float_type_spec.rb +37 -0
  109. data/spec/integration/numeric_validator/gte_with_float_type_spec.rb +37 -0
  110. data/spec/integration/numeric_validator/integer_only_true_spec.rb +91 -0
  111. data/spec/integration/numeric_validator/integer_type_spec.rb +86 -0
  112. data/spec/integration/numeric_validator/lt_with_float_type_spec.rb +37 -0
  113. data/spec/integration/numeric_validator/lte_with_float_type_spec.rb +37 -0
  114. data/spec/integration/numeric_validator/spec_helper.rb +5 -0
  115. data/spec/integration/primitive_validator/primitive_validator_spec.rb +92 -0
  116. data/spec/integration/primitive_validator/spec_helper.rb +5 -0
  117. data/spec/integration/pure_ruby_objects/plain_old_ruby_object_validation_spec.rb +118 -0
  118. data/spec/integration/required_field_validator/association_spec.rb +72 -0
  119. data/spec/integration/required_field_validator/boolean_type_value_spec.rb +155 -0
  120. data/spec/integration/required_field_validator/date_type_value_spec.rb +127 -0
  121. data/spec/integration/required_field_validator/datetime_type_value_spec.rb +127 -0
  122. data/spec/integration/required_field_validator/float_type_value_spec.rb +131 -0
  123. data/spec/integration/required_field_validator/integer_type_value_spec.rb +99 -0
  124. data/spec/integration/required_field_validator/plain_old_ruby_object_spec.rb +35 -0
  125. data/spec/integration/required_field_validator/shared_examples.rb +26 -0
  126. data/spec/integration/required_field_validator/spec_helper.rb +7 -0
  127. data/spec/integration/required_field_validator/string_type_value_spec.rb +167 -0
  128. data/spec/integration/required_field_validator/text_type_value_spec.rb +49 -0
  129. data/spec/integration/shared/default_validation_context.rb +13 -0
  130. data/spec/integration/shared/valid_and_invalid_model.rb +35 -0
  131. data/spec/integration/uniqueness_validator/spec_helper.rb +5 -0
  132. data/spec/integration/uniqueness_validator/uniqueness_validator_spec.rb +116 -0
  133. data/spec/integration/within_validator/spec_helper.rb +5 -0
  134. data/spec/integration/within_validator/within_validator_spec.rb +168 -0
  135. data/spec/public/resource_spec.rb +105 -0
  136. data/spec/rcov.opts +6 -0
  137. data/spec/spec.opts +4 -0
  138. data/spec/spec_helper.rb +29 -0
  139. data/spec/unit/contextual_validators/emptiness_spec.rb +50 -0
  140. data/spec/unit/contextual_validators/execution_spec.rb +48 -0
  141. data/spec/unit/contextual_validators/spec_helper.rb +37 -0
  142. data/spec/unit/generic_validator/equality_operator_spec.rb +26 -0
  143. data/spec/unit/generic_validator/optional_spec.rb +54 -0
  144. data/spec/unit/validation_errors/adding_spec.rb +54 -0
  145. data/spec/unit/validation_errors/emptiness_spec.rb +38 -0
  146. data/spec/unit/validation_errors/enumerable_spec.rb +32 -0
  147. data/spec/unit/validation_errors/reading_spec.rb +35 -0
  148. data/spec/unit/validation_errors/respond_to_spec.rb +15 -0
  149. data/spec/unit/validators/within_validator_spec.rb +23 -0
  150. data/tasks/spec.rake +38 -0
  151. data/tasks/yard.rake +9 -0
  152. data/tasks/yardstick.rake +19 -0
  153. metadata +256 -0
@@ -0,0 +1,182 @@
1
+ module DataMapper
2
+ module Validations
3
+ # @author Guy van den Berg
4
+ # @since 0.9
5
+ class NumericalityValidator < GenericValidator
6
+
7
+ def call(target)
8
+ value = target.validation_property_value(field_name)
9
+ return true if optional?(value)
10
+
11
+ errors = []
12
+
13
+ validate_with(integer_only? ? :integer : :numeric, value, errors)
14
+
15
+ add_errors(target, errors)
16
+
17
+ # if the number is invalid, skip further tests
18
+ return false if errors.any?
19
+
20
+ [ :gt, :lt, :gte, :lte, :eq, :ne ].each do |validation_type|
21
+ validate_with(validation_type, value, errors)
22
+ end
23
+
24
+ add_errors(target, errors)
25
+
26
+ errors.empty?
27
+ end
28
+
29
+ private
30
+
31
+ def integer_only?
32
+ options[:only_integer] || options.fetch(:integer_only, false)
33
+ end
34
+
35
+ def value_as_string(value)
36
+ case value
37
+ # Avoid Scientific Notation in Float to_s
38
+ when Float then value.to_d.to_s('F')
39
+ when BigDecimal then value.to_s('F')
40
+ else value.to_s
41
+ end
42
+ end
43
+
44
+ def add_errors(target, errors)
45
+ return if errors.empty?
46
+
47
+ if options.key?(:message)
48
+ add_error(target, options[:message], field_name)
49
+ else
50
+ errors.each do |error_message|
51
+ add_error(target, error_message, field_name)
52
+ end
53
+ end
54
+ end
55
+
56
+ def validate_with(validation_type, value, errors)
57
+ send("validate_#{validation_type}", value, errors)
58
+ end
59
+
60
+ def validate_with_comparison(value, cmp, expected, error_message_name, errors, negated = false)
61
+ return if expected.nil?
62
+
63
+ # XXX: workaround for jruby. This is needed because the jruby
64
+ # compiler optimizes a bit too far with magic variables like $~.
65
+ # the value.send line sends $~. Inserting this line makes sure the
66
+ # jruby compiler does not optimise here.
67
+ # see http://jira.codehaus.org/browse/JRUBY-3765
68
+ $~ = nil if RUBY_PLATFORM[/java/]
69
+
70
+ comparison = value.send(cmp, expected)
71
+ return if negated ? !comparison : comparison
72
+
73
+ errors << ValidationErrors.default_error_message(
74
+ error_message_name,
75
+ field_name,
76
+ expected
77
+ )
78
+ end
79
+
80
+ def validate_integer(value, errors)
81
+ validate_with_comparison(value_as_string(value), :=~, /\A[+-]?\d+\z/, :not_an_integer, errors)
82
+ end
83
+
84
+ def validate_numeric(value, errors)
85
+ precision = options[:precision]
86
+ scale = options[:scale]
87
+
88
+ regexp = if precision && scale
89
+ if precision > scale && scale == 0
90
+ /\A[+-]?(?:\d{1,#{precision}}(?:\.0)?)\z/
91
+ elsif precision > scale
92
+ /\A[+-]?(?:\d{1,#{precision - scale}}|\d{0,#{precision - scale}}\.\d{1,#{scale}})\z/
93
+ elsif precision == scale
94
+ /\A[+-]?(?:0(?:\.\d{1,#{scale}})?)\z/
95
+ else
96
+ raise ArgumentError, "Invalid precision #{precision.inspect} and scale #{scale.inspect} for #{field_name} (value: #{value.inspect} #{value.class})"
97
+ end
98
+ else
99
+ /\A[+-]?(?:\d+|\d*\.\d+)\z/
100
+ end
101
+
102
+ validate_with_comparison(value_as_string(value), :=~, regexp, :not_a_number, errors)
103
+ end
104
+
105
+ def validate_gt(value, errors)
106
+ validate_with_comparison(value, :>, options[:gt] || options[:greater_than], :greater_than, errors)
107
+ end
108
+
109
+ def validate_lt(value, errors)
110
+ validate_with_comparison(value, :<, options[:lt] || options[:less_than], :less_than, errors)
111
+ end
112
+
113
+ def validate_gte(value, errors)
114
+ validate_with_comparison(value, :>=, options[:gte] || options[:greater_than_or_equal_to], :greater_than_or_equal_to, errors)
115
+ end
116
+
117
+ def validate_lte(value, errors)
118
+ validate_with_comparison(value, :<=, options[:lte] || options[:less_than_or_equal_to], :less_than_or_equal_to, errors)
119
+ end
120
+
121
+ def validate_eq(value, errors)
122
+ eq = options[:eq] || options[:equal] || options[:equals] || options[:exactly] || options[:equal_to]
123
+ validate_with_comparison(value, :==, eq, :equal_to, errors)
124
+ end
125
+
126
+ def validate_ne(value, errors)
127
+ validate_with_comparison(value, :==, options[:ne] || options[:not_equal_to], :not_equal_to, errors, true)
128
+ end
129
+
130
+ end # class NumericalityValidator
131
+
132
+ module ValidatesNumericality
133
+ extend Deprecate
134
+
135
+ # Validate whether a field is numeric.
136
+ #
137
+ # @option [Boolean] :allow_nil
138
+ # true if number can be nil, false if not.
139
+ #
140
+ # @option [Boolean] :allow_blank
141
+ # true if number can be blank, false if not.
142
+ #
143
+ # @option [String] :message
144
+ # Custom error message, also can be a callable object that takes
145
+ # an object (for pure Ruby objects) or object and property
146
+ # (for DM resources).
147
+ #
148
+ # @option [Numeric] :precision
149
+ # Required precision of a value.
150
+ #
151
+ # @option [Numeric] :scale
152
+ # Required scale of a value.
153
+ #
154
+ # @option [Numeric] :gte
155
+ # 'Greater than or equal to' requirement.
156
+ #
157
+ # @option [Numeric] :lte
158
+ # 'Less than or equal to' requirement.
159
+ #
160
+ # @option [Numeric] :lt
161
+ # 'Less than' requirement.
162
+ #
163
+ # @option [Numeric] :gt
164
+ # 'Greater than' requirement.
165
+ #
166
+ # @option [Numeric] :eq
167
+ # 'Equal' requirement.
168
+ #
169
+ # @option [Numeric] :ne
170
+ # 'Not equal' requirement.
171
+ #
172
+ # @option [Boolean] :integer_only
173
+ # Use to restrict allowed values to integers.
174
+ #
175
+ def validates_numericality_of(*fields)
176
+ validators.add(NumericalityValidator, *fields)
177
+ end
178
+
179
+ deprecate :validates_is_number, :validates_numericality_of
180
+ end # module ValidatesIsNumber
181
+ end # module Validations
182
+ end # module DataMapper
@@ -0,0 +1,58 @@
1
+ module DataMapper
2
+ module Validations
3
+ # @author Dirkjan Bussink
4
+ # @since 0.9
5
+ class PrimitiveTypeValidator < GenericValidator
6
+
7
+ def call(target)
8
+ value = target.validation_property_value(field_name)
9
+ property = get_resource_property(target, field_name)
10
+
11
+ return true if value.nil? || property.primitive?(value)
12
+
13
+ error_message = @options[:message] || default_error(property)
14
+ add_error(target, error_message, field_name)
15
+
16
+ false
17
+ end
18
+
19
+ protected
20
+
21
+ def default_error(property)
22
+ ValidationErrors.default_error_message(
23
+ :primitive,
24
+ field_name,
25
+ property.primitive
26
+ )
27
+ end
28
+
29
+ end # class PrimitiveTypeValidator
30
+
31
+ module ValidatesPrimitiveType
32
+ extend Deprecate
33
+
34
+ # Validates that the specified attribute is of the correct primitive
35
+ # type.
36
+ #
37
+ # @example Usage
38
+ # require 'dm-validations'
39
+ #
40
+ # class Person
41
+ # include DataMapper::Resource
42
+ #
43
+ # property :birth_date, Date
44
+ #
45
+ # validates_primitive_type_of :birth_date
46
+ #
47
+ # # a call to valid? will return false unless
48
+ # # the birth_date is something that can be properly
49
+ # # casted into a Date object.
50
+ # end
51
+ def validates_primitive_type_of(*fields)
52
+ validators.add(PrimitiveTypeValidator, *fields)
53
+ end
54
+
55
+ deprecate :validates_is_primitive, :validates_primitive_type_of
56
+ end # module ValidatesPresent
57
+ end # module Validations
58
+ end # module DataMapper
@@ -0,0 +1,83 @@
1
+ module DataMapper
2
+ module Validations
3
+ # @author Guy van den Berg
4
+ # @since 0.9
5
+ class PresenceValidator < GenericValidator
6
+
7
+ def call(target)
8
+ value = target.validation_property_value(field_name)
9
+ property = get_resource_property(target, field_name)
10
+ return true if present?(value, property)
11
+
12
+ error_message = @options[:message] || default_error(property)
13
+ add_error(target, error_message, field_name)
14
+
15
+ false
16
+ end
17
+
18
+ protected
19
+
20
+ # Boolean property types are considered present if non-nil.
21
+ # Other property types are considered present if non-blank.
22
+ # Non-properties are considered present if non-blank.
23
+ def present?(value, property)
24
+ boolean_type?(property) ? !value.nil? : !DataMapper::Ext.blank?(value)
25
+ end
26
+
27
+ def default_error(property)
28
+ actual = boolean_type?(property) ? :nil : :blank
29
+ ValidationErrors.default_error_message(actual, field_name)
30
+ end
31
+
32
+ # Is the property a boolean property?
33
+ #
34
+ # @return [Boolean]
35
+ # Returns true for Boolean, ParanoidBoolean, TrueClass and other
36
+ # properties. Returns false for other property types or for
37
+ # non-properties.
38
+ def boolean_type?(property)
39
+ property ? property.primitive == TrueClass : false
40
+ end
41
+
42
+ end # class PresenceValidator
43
+
44
+ module ValidatesPresence
45
+ extend Deprecate
46
+
47
+ ##
48
+ # Validates that the specified attribute is present.
49
+ #
50
+ # For most property types "being present" is the same as being "not
51
+ # blank" as determined by the attribute's #blank? method. However, in
52
+ # the case of Boolean, "being present" means not nil; i.e. true or
53
+ # false.
54
+ #
55
+ # @note
56
+ # dm-core's support lib adds the blank? method to many classes,
57
+ #
58
+ # @see lib/dm-core/support/blank.rb (dm-core) for more information.
59
+ #
60
+ # @example Usage
61
+ # require 'dm-validations'
62
+ #
63
+ # class Page
64
+ # include DataMapper::Resource
65
+ #
66
+ # property :required_attribute, String
67
+ # property :another_required, String
68
+ # property :yet_again, String
69
+ #
70
+ # validates_presence_of :required_attribute
71
+ # validates_presence_of :another_required, :yet_again
72
+ #
73
+ # # a call to valid? will return false unless
74
+ # # all three attributes are !blank?
75
+ # end
76
+ def validates_presence_of(*fields)
77
+ validators.add(PresenceValidator, *fields)
78
+ end
79
+
80
+ deprecate :validates_present, :validates_presence_of
81
+ end # module ValidatesPresent
82
+ end # module Validations
83
+ end # module DataMapper
@@ -0,0 +1,67 @@
1
+ module DataMapper
2
+ module Validations
3
+ # @author Guy van den Berg
4
+ # @since 0.9
5
+ class UniquenessValidator < GenericValidator
6
+
7
+ include DataMapper::Assertions
8
+
9
+ def initialize(field_name, options = {})
10
+ if options.has_key?(:scope)
11
+ assert_kind_of('scope', options[:scope], Array, Symbol)
12
+ end
13
+
14
+ super
15
+
16
+ set_optional_by_default
17
+ end
18
+
19
+ def call(target)
20
+ return true if valid?(target)
21
+
22
+ error_message = @options[:message] || ValidationErrors.default_error_message(:taken, field_name)
23
+ add_error(target, error_message, field_name)
24
+
25
+ false
26
+ end
27
+
28
+ def valid?(target)
29
+ value = target.validation_property_value(field_name)
30
+ return true if optional?(value)
31
+
32
+ opts = {
33
+ :fields => target.model.key(target.repository.name),
34
+ field_name => value,
35
+ }
36
+
37
+ Array(@options[:scope]).each { |subject|
38
+ unless target.respond_to?(subject)
39
+ raise(ArgumentError,"Could not find property to scope by: #{subject}. Note that :unique does not currently support arbitrarily named groups, for that you should use :unique_index with an explicit validates_uniqueness_of.")
40
+ end
41
+
42
+ opts[subject] = target.__send__(subject)
43
+ }
44
+
45
+ resource = DataMapper.repository(target.repository.name) do
46
+ target.model.first(opts)
47
+ end
48
+
49
+ return true if resource.nil?
50
+ target.saved? && resource.key == target.key
51
+ end
52
+
53
+ end # class UniquenessValidator
54
+
55
+ module ValidatesUniqueness
56
+ extend Deprecate
57
+
58
+ # Validate the uniqueness of a field
59
+ #
60
+ def validates_uniqueness_of(*fields)
61
+ validators.add(UniquenessValidator, *fields)
62
+ end
63
+
64
+ deprecate :validates_is_unique, :validates_uniqueness_of
65
+ end # module ValidatesIsUnique
66
+ end # module Validations
67
+ end # module DataMapper
@@ -0,0 +1,74 @@
1
+ module DataMapper
2
+ module Validations
3
+ # @author Guy van den Berg
4
+ # @since 0.9
5
+ class WithinValidator < GenericValidator
6
+
7
+ def initialize(field_name, options={})
8
+ super
9
+
10
+ @options[:set] = [] unless @options.has_key?(:set)
11
+ end
12
+
13
+ def call(target)
14
+ value = target.validation_property_value(field_name)
15
+ return true if optional?(value)
16
+ return true if @options[:set].include?(value)
17
+
18
+ n = 1.0/0
19
+ set = @options[:set]
20
+ msg = @options[:message]
21
+
22
+ if set.is_a?(Range)
23
+ if set.first != -n && set.last != n
24
+ error_message = msg || ValidationErrors.default_error_message(:value_between, field_name, set.first, set.last)
25
+ elsif set.first == -n
26
+ error_message = msg || ValidationErrors.default_error_message(:less_than_or_equal_to, field_name, set.last)
27
+ elsif set.last == n
28
+ error_message = msg || ValidationErrors.default_error_message(:greater_than_or_equal_to, field_name, set.first)
29
+ end
30
+ else
31
+ error_message = msg || ValidationErrors.default_error_message(:inclusion, field_name, set.to_a.join(', '))
32
+ end
33
+
34
+ add_error(target, error_message, field_name)
35
+
36
+ false
37
+ end
38
+
39
+
40
+ end # class WithinValidator
41
+
42
+ module ValidatesWithin
43
+ ##
44
+ # Validates that the value of a field is within a range/set.
45
+ #
46
+ # This validation is defined by passing a field along with a :set
47
+ # parameter. The :set can be a Range or any object which responds
48
+ # to the #include? method (an array, for example).
49
+ #
50
+ # @example Usage
51
+ # require 'dm-validations'
52
+ #
53
+ # class Review
54
+ # include DataMapper::Resource
55
+ #
56
+ # STATES = ['new', 'in_progress', 'published', 'archived']
57
+ #
58
+ # property :title, String
59
+ # property :body, String
60
+ # property :review_state, String
61
+ # property :rating, Integer
62
+ #
63
+ # validates_within :review_state, :set => STATES
64
+ # validates_within :rating, :set => 1..5
65
+ #
66
+ # # a call to valid? will return false unless
67
+ # # the two properties conform to their sets
68
+ # end
69
+ def validates_within(*fields)
70
+ validators.add(WithinValidator, *fields)
71
+ end
72
+ end # module ValidatesWithin
73
+ end # module Validations
74
+ end # module DataMapper