ardm-validations 1.2.0

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