remarkable_activerecord 3.1.8 → 3.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/CHANGELOG +140 -138
  2. data/LICENSE +20 -20
  3. data/README +80 -80
  4. data/lib/remarkable_activerecord.rb +29 -29
  5. data/lib/remarkable_activerecord/base.rb +248 -237
  6. data/lib/remarkable_activerecord/describe.rb +27 -27
  7. data/lib/remarkable_activerecord/human_names.rb +36 -36
  8. data/lib/remarkable_activerecord/matchers/accept_nested_attributes_for_matcher.rb +30 -30
  9. data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +59 -59
  10. data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +85 -94
  11. data/lib/remarkable_activerecord/matchers/association_matcher.rb +283 -283
  12. data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +68 -68
  13. data/lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb +38 -38
  14. data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +73 -73
  15. data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +30 -30
  16. data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +85 -85
  17. data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +50 -50
  18. data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +97 -97
  19. data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +44 -44
  20. data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +53 -53
  21. data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +52 -52
  22. data/lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb +150 -150
  23. data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +181 -181
  24. data/lib/remarkable_activerecord/matchers/validate_presence_of_matcher.rb +29 -29
  25. data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +233 -233
  26. data/locale/en.yml +261 -261
  27. data/spec/accept_nested_attributes_for_matcher_spec.rb +1 -1
  28. data/spec/allow_mass_assignment_of_matcher_spec.rb +90 -82
  29. data/spec/allow_values_for_matcher_spec.rb +72 -63
  30. data/spec/association_matcher_spec.rb +612 -612
  31. data/spec/describe_spec.rb +3 -3
  32. data/spec/have_column_matcher_spec.rb +73 -73
  33. data/spec/have_default_scope_matcher_spec.rb +1 -1
  34. data/spec/have_index_matcher_spec.rb +87 -87
  35. data/spec/have_readonly_attributes_matcher_spec.rb +47 -47
  36. data/spec/have_scope_matcher_spec.rb +77 -77
  37. data/spec/model_builder.rb +101 -101
  38. data/spec/rcov.opts +1 -1
  39. data/spec/spec.opts +4 -4
  40. data/spec/spec_helper.rb +27 -27
  41. data/spec/validate_acceptance_of_matcher_spec.rb +68 -68
  42. data/spec/validate_associated_matcher_spec.rb +121 -121
  43. data/spec/validate_confirmation_of_matcher_spec.rb +58 -58
  44. data/spec/validate_length_of_matcher_spec.rb +218 -218
  45. data/spec/validate_numericality_of_matcher_spec.rb +179 -179
  46. data/spec/validate_presence_of_matcher_spec.rb +56 -56
  47. data/spec/validate_uniqueness_of_matcher_spec.rb +164 -164
  48. metadata +5 -5
@@ -1,57 +1,57 @@
1
- require File.join(File.dirname(__FILE__), 'allow_values_for_matcher')
2
-
3
- module Remarkable
4
- module ActiveRecord
5
- module Matchers
6
- class ValidateInclusionOfMatcher < AllowValuesForMatcher #:nodoc:
1
+ require File.join(File.dirname(__FILE__), 'allow_values_for_matcher')
2
+
3
+ module Remarkable
4
+ module ActiveRecord
5
+ module Matchers
6
+ class ValidateInclusionOfMatcher < AllowValuesForMatcher #:nodoc:
7
7
  # Don't allow it to behave in the negative way.
8
- undef_method :does_not_match?
8
+ undef_method :does_not_match?
9
9
 
10
10
  default_options :message => :inclusion
11
-
12
- protected
13
-
14
- def valid_values
15
- @options[:in]
16
- end
17
-
18
- def invalid_values
19
- if @in_range
20
- [ @options[:in].first - 1, @options[:in].last + 1 ]
11
+
12
+ protected
13
+
14
+ def valid_values
15
+ @options[:in]
16
+ end
17
+
18
+ def invalid_values
19
+ if @in_range
20
+ [ @options[:in].first - 1, @options[:in].last + 1 ]
21
21
  else
22
22
  value = @options[:in].select{ |i| i.is_a?(String) }.max
23
- value ? [ value.next ] : []
24
- end
25
- end
26
-
27
- end
28
-
29
- # Ensures that given values are valid for the attribute. If a range
30
- # is given, ensures that the attribute is valid in the given range.
31
- #
32
- # If you give that :size accepts ["S", "M", "L"], it will test that "T"
33
- # (the next of the array max value) is not allowed.
34
- #
35
- # == Options
36
- #
37
- # * <tt>:in</tt> - values to test inclusion.
38
- # * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
39
- # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
40
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
41
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
42
- #
43
- # == Examples
44
- #
45
- # should_validate_inclusion_of :size, :in => ["S", "M", "L", "XL"]
46
- # should_validate_inclusion_of :age, :in => 18..100
47
- #
48
- # it { should validate_inclusion_of(:size, :in => ["S", "M", "L", "XL"]) }
49
- # it { should validate_inclusion_of(:age, :in => 18..100) }
50
- #
51
- def validate_inclusion_of(*args, &block)
52
- ValidateInclusionOfMatcher.new(*args, &block).spec(self)
53
- end
54
-
55
- end
56
- end
57
- end
23
+ value ? [ value.next ] : []
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ # Ensures that given values are valid for the attribute. If a range
30
+ # is given, ensures that the attribute is valid in the given range.
31
+ #
32
+ # If you give that :size accepts ["S", "M", "L"], it will test that "T"
33
+ # (the next of the array max value) is not allowed.
34
+ #
35
+ # == Options
36
+ #
37
+ # * <tt>:in</tt> - values to test inclusion.
38
+ # * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
39
+ # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
40
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
41
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.inclusion')</tt>
42
+ #
43
+ # == Examples
44
+ #
45
+ # should_validate_inclusion_of :size, :in => ["S", "M", "L", "XL"]
46
+ # should_validate_inclusion_of :age, :in => 18..100
47
+ #
48
+ # it { should validate_inclusion_of(:size, :in => ["S", "M", "L", "XL"]) }
49
+ # it { should validate_inclusion_of(:age, :in => 18..100) }
50
+ #
51
+ def validate_inclusion_of(*args, &block)
52
+ ValidateInclusionOfMatcher.new(*args, &block).spec(self)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -1,150 +1,150 @@
1
- module Remarkable
2
- module ActiveRecord
3
- module Matchers
4
- class ValidateLengthOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
- arguments :collection => :attributes, :as => :attribute
6
-
7
- optional :within, :alias => :in
8
- optional :minimum, :maximum, :is
9
- optional :token, :separator, :with_kind_of
10
- optional :allow_nil, :allow_blank, :default => true
11
- optional :message, :too_short, :too_long, :wrong_length
12
-
13
- collection_assertions :less_than_min_length?, :exactly_min_length?,
14
- :more_than_max_length?, :exactly_max_length?,
15
- :allow_nil?, :allow_blank?
16
-
17
- before_assert do
18
- # Reassign :in to :within
19
- @options[:within] ||= @options.delete(:in) if @options.key?(:in)
20
-
21
- if @options[:is]
22
- @min_value, @max_value = @options[:is], @options[:is]
23
- elsif @options[:within]
24
- @min_value, @max_value = @options[:within].first, @options[:within].last
25
- elsif @options[:maximum]
26
- @min_value, @max_value = nil, @options[:maximum]
27
- elsif @options[:minimum]
28
- @min_value, @max_value = @options[:minimum], nil
29
- end
30
- end
31
-
32
- default_options :too_short => :too_short, :too_long => :too_long, :wrong_length => :wrong_length
33
-
34
- protected
35
- def allow_nil?
36
- super(default_message_for(:too_short))
37
- end
38
-
39
- def allow_blank?
40
- super(default_message_for(:too_short))
41
- end
42
-
43
- def less_than_min_length?
44
- @min_value.nil? || @min_value <= 1 || bad?(value_for_length(@min_value - 1), default_message_for(:too_short))
45
- end
46
-
47
- def exactly_min_length?
48
- @min_value.nil? || @min_value <= 0 || good?(value_for_length(@min_value), default_message_for(:too_short))
49
- end
50
-
51
- def more_than_max_length?
52
- @max_value.nil? || bad?(value_for_length(@max_value + 1), default_message_for(:too_long))
53
- end
54
-
55
- def exactly_max_length?
56
- @max_value.nil? || @min_value == @max_value || good?(value_for_length(@max_value), default_message_for(:too_long))
57
- end
58
-
59
- def value_for_length(value)
60
- if @options[:with_kind_of]
61
- [@options[:with_kind_of].new] * value
62
- else
63
- ([@options.fetch(:token, 'x')] * value).join(@options.fetch(:separator, ''))
64
- end
65
- end
66
-
67
- def interpolation_options
68
- { :minimum => @min_value, :maximum => @max_value }
69
- end
70
-
71
- # Returns the default message for the validation type.
72
- # If user supplied :message, it will return it. Otherwise it will return
73
- # wrong_length on :is validation and :too_short or :too_long in the other
74
- # types.
75
- #
76
- def default_message_for(validation_type)
77
- return :message if @options[:message]
78
- @options.key?(:is) ? :wrong_length : validation_type
79
- end
80
- end
81
-
82
- # Validates the length of the given attributes. You have also to supply
83
- # one of the following options: minimum, maximum, is or within.
84
- #
85
- # Note: this method is also aliased as <tt>validate_size_of</tt>.
86
- #
87
- # == Options
88
- #
89
- # * <tt>:minimum</tt> - The minimum size of the attribute.
90
- # * <tt>:maximum</tt> - The maximum size of the attribute.
91
- # * <tt>:is</tt> - The exact size of the attribute.
92
- # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
93
- # * <tt>:in</tt> - A synonym(or alias) for :within.
94
- # * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
95
- # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
96
- # * <tt>:too_short</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is too short.
97
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % range.first</tt>
98
- # * <tt>:too_long</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is too long.
99
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.too_long') % range.last</tt>
100
- # * <tt>:wrong_length</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is the wrong length.
101
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % range.last</tt>
102
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
103
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % value</tt>
104
- #
105
- # It also accepts an extra option called :with_kind_of. If you are validating
106
- # the size of an association array, you have to specify the kind of the array
107
- # being validated. For example, if your post accepts maximum 10 comments, you
108
- # can do:
109
- #
110
- # should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
111
- #
112
- # Finally, it also accepts :token and :separator, to specify how the
113
- # tokenizer should work. For example, if you are splitting the attribute
114
- # per word:
115
- #
116
- # validates_length_of :essay, :minimum => 100, :tokenizer => lambda {|str| str.scan(/\w+/) }
117
- #
118
- # You could do this:
119
- #
120
- # should_validate_length_of :essay, :minimum => 100, :token => "word", :separator => " "
121
- #
122
- # == Gotcha
123
- #
124
- # In Rails 2.3.x, when :message is supplied, it overwrites the messages
125
- # supplied in :wrong_length, :too_short and :too_long. However, in earlier
126
- # versions, Rails ignores the :message option.
127
- #
128
- # == Examples
129
- #
130
- # it { should validate_length_of(:password).within(6..20) }
131
- # it { should validate_length_of(:password).maximum(20) }
132
- # it { should validate_length_of(:password).minimum(6) }
133
- # it { should validate_length_of(:age).is(18) }
134
- #
135
- # should_validate_length_of :password, :within => 6..20
136
- # should_validate_length_of :password, :maximum => 20
137
- # should_validate_length_of :password, :minimum => 6
138
- # should_validate_length_of :age, :is => 18
139
- #
140
- # should_validate_length_of :password do |m|
141
- # m.minimum 6
142
- # m.maximum 20
143
- # end
144
- #
145
- def validate_length_of(*attributes, &block)
146
- ValidateLengthOfMatcher.new(*attributes, &block).spec(self)
147
- end
148
- end
149
- end
150
- end
1
+ module Remarkable
2
+ module ActiveRecord
3
+ module Matchers
4
+ class ValidateLengthOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
+ arguments :collection => :attributes, :as => :attribute
6
+
7
+ optional :within, :alias => :in
8
+ optional :minimum, :maximum, :is
9
+ optional :token, :separator, :with_kind_of
10
+ optional :allow_nil, :allow_blank, :default => true
11
+ optional :message, :too_short, :too_long, :wrong_length
12
+
13
+ collection_assertions :less_than_min_length?, :exactly_min_length?,
14
+ :more_than_max_length?, :exactly_max_length?,
15
+ :allow_nil?, :allow_blank?
16
+
17
+ before_assert do
18
+ # Reassign :in to :within
19
+ @options[:within] ||= @options.delete(:in) if @options.key?(:in)
20
+
21
+ if @options[:is]
22
+ @min_value, @max_value = @options[:is], @options[:is]
23
+ elsif @options[:within]
24
+ @min_value, @max_value = @options[:within].first, @options[:within].last
25
+ elsif @options[:maximum]
26
+ @min_value, @max_value = nil, @options[:maximum]
27
+ elsif @options[:minimum]
28
+ @min_value, @max_value = @options[:minimum], nil
29
+ end
30
+ end
31
+
32
+ default_options :too_short => :too_short, :too_long => :too_long, :wrong_length => :wrong_length
33
+
34
+ protected
35
+ def allow_nil?
36
+ super(default_message_for(:too_short))
37
+ end
38
+
39
+ def allow_blank?
40
+ super(default_message_for(:too_short))
41
+ end
42
+
43
+ def less_than_min_length?
44
+ @min_value.nil? || @min_value <= 1 || bad?(value_for_length(@min_value - 1), default_message_for(:too_short))
45
+ end
46
+
47
+ def exactly_min_length?
48
+ @min_value.nil? || @min_value <= 0 || good?(value_for_length(@min_value), default_message_for(:too_short))
49
+ end
50
+
51
+ def more_than_max_length?
52
+ @max_value.nil? || bad?(value_for_length(@max_value + 1), default_message_for(:too_long))
53
+ end
54
+
55
+ def exactly_max_length?
56
+ @max_value.nil? || @min_value == @max_value || good?(value_for_length(@max_value), default_message_for(:too_long))
57
+ end
58
+
59
+ def value_for_length(value)
60
+ if @options[:with_kind_of]
61
+ [@options[:with_kind_of].new] * value
62
+ else
63
+ ([@options.fetch(:token, 'x')] * value).join(@options.fetch(:separator, ''))
64
+ end
65
+ end
66
+
67
+ def interpolation_options
68
+ { :minimum => @min_value, :maximum => @max_value }
69
+ end
70
+
71
+ # Returns the default message for the validation type.
72
+ # If user supplied :message, it will return it. Otherwise it will return
73
+ # wrong_length on :is validation and :too_short or :too_long in the other
74
+ # types.
75
+ #
76
+ def default_message_for(validation_type)
77
+ return :message if @options[:message]
78
+ @options.key?(:is) ? :wrong_length : validation_type
79
+ end
80
+ end
81
+
82
+ # Validates the length of the given attributes. You have also to supply
83
+ # one of the following options: minimum, maximum, is or within.
84
+ #
85
+ # Note: this method is also aliased as <tt>validate_size_of</tt>.
86
+ #
87
+ # == Options
88
+ #
89
+ # * <tt>:minimum</tt> - The minimum size of the attribute.
90
+ # * <tt>:maximum</tt> - The maximum size of the attribute.
91
+ # * <tt>:is</tt> - The exact size of the attribute.
92
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
93
+ # * <tt>:in</tt> - A synonym(or alias) for :within.
94
+ # * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
95
+ # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
96
+ # * <tt>:too_short</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is too short.
97
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.too_short') % range.first</tt>
98
+ # * <tt>:too_long</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is too long.
99
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.too_long') % range.last</tt>
100
+ # * <tt>:wrong_length</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt> when attribute is the wrong length.
101
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % range.last</tt>
102
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
103
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % value</tt>
104
+ #
105
+ # It also accepts an extra option called :with_kind_of. If you are validating
106
+ # the size of an association array, you have to specify the kind of the array
107
+ # being validated. For example, if your post accepts maximum 10 comments, you
108
+ # can do:
109
+ #
110
+ # should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
111
+ #
112
+ # Finally, it also accepts :token and :separator, to specify how the
113
+ # tokenizer should work. For example, if you are splitting the attribute
114
+ # per word:
115
+ #
116
+ # validates_length_of :essay, :minimum => 100, :tokenizer => lambda {|str| str.scan(/\w+/) }
117
+ #
118
+ # You could do this:
119
+ #
120
+ # should_validate_length_of :essay, :minimum => 100, :token => "word", :separator => " "
121
+ #
122
+ # == Gotcha
123
+ #
124
+ # In Rails 2.3.x, when :message is supplied, it overwrites the messages
125
+ # supplied in :wrong_length, :too_short and :too_long. However, in earlier
126
+ # versions, Rails ignores the :message option.
127
+ #
128
+ # == Examples
129
+ #
130
+ # it { should validate_length_of(:password).within(6..20) }
131
+ # it { should validate_length_of(:password).maximum(20) }
132
+ # it { should validate_length_of(:password).minimum(6) }
133
+ # it { should validate_length_of(:age).is(18) }
134
+ #
135
+ # should_validate_length_of :password, :within => 6..20
136
+ # should_validate_length_of :password, :maximum => 20
137
+ # should_validate_length_of :password, :minimum => 6
138
+ # should_validate_length_of :age, :is => 18
139
+ #
140
+ # should_validate_length_of :password do |m|
141
+ # m.minimum 6
142
+ # m.maximum 20
143
+ # end
144
+ #
145
+ def validate_length_of(*attributes, &block)
146
+ ValidateLengthOfMatcher.new(*attributes, &block).spec(self)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -1,188 +1,188 @@
1
- module Remarkable
2
- module ActiveRecord
3
- module Matchers
4
- class ValidateNumericalityOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
- arguments :collection => :attributes, :as => :attribute
6
-
7
- optional :equal_to, :greater_than_or_equal_to, :greater_than,
8
- :less_than_or_equal_to, :less_than, :message
9
-
10
- optional :only_integer, :odd, :even, :allow_nil, :allow_blank, :default => true
11
-
12
- collection_assertions :only_numeric_values?, :allow_blank?, :allow_nil?,
13
- :only_integer?, :only_odd?, :only_even?, :equals_to?,
14
- :less_than_minimum?, :more_than_maximum?
15
-
16
- # Before assertions, we rearrange the values.
17
- #
18
- # Notice that :less_than gives a maximum value while :more_than given
19
- # a minimum value. While :equal_to generate both.
20
- #
21
- before_assert do
22
- @maximum_values = {}
23
- @minimum_values = {}
24
-
25
- if value = @options[:equal_to]
26
- @maximum_values[:equal_to] = value
27
- @minimum_values[:equal_to] = value
28
- elsif value = @options[:less_than]
29
- @maximum_values[:less_than] = value - 1
30
- elsif value = @options[:greater_than]
31
- @minimum_values[:greater_than] = value + 1
32
- elsif value = @options[:less_than_or_equal_to]
33
- @maximum_values[:less_than_or_equal_to] = value
34
- elsif value = @options[:greater_than_or_equal_to]
35
- @minimum_values[:greater_than_or_equal_to] = value
36
- end
37
- end
38
-
39
- private
40
-
41
- def allow_nil?
42
- super(default_message_for(:not_a_number))
43
- end
44
-
45
- def allow_blank?
46
- super(default_message_for(:not_a_number))
47
- end
48
-
49
- def only_numeric_values?
50
- bad?("abcd", default_message_for(:not_a_number))
51
- end
52
-
53
- def only_integer?
54
- assert_bad_or_good_if_key(:only_integer, valid_value_for_test.to_f, default_message_for(:not_a_number))
55
- end
56
-
57
- # In ActiveRecord, when we supply :even, does not matter the value, it
58
- # considers that should even values should be accepted.
59
- #
60
- def only_even?
61
- return true unless @options[:even]
62
- bad?(even_valid_value_for_test + 1, default_message_for(:even))
63
- end
64
-
65
- # In ActiveRecord, when we supply :odd, does not matter the value, it
66
- # considers that should odd values should be accepted.
67
- #
68
- def only_odd?
69
- return true unless @options[:odd]
70
- bad?(even_valid_value_for_test, default_message_for(:odd))
71
- end
72
-
73
- # Check equal_to for all registered values.
74
- #
75
- def equals_to?
76
- values = {}
77
- @maximum_values.each { |k, v| values[k] = v }
78
- @minimum_values.each { |k, v| values[k] = v }
79
-
80
- values.each do |key, value|
81
- return false, :count => value unless good?(value, default_message_for(key))
82
- end
83
- true
84
- end
85
-
86
- # Check more_than_maximum? for equal_to, less_than and
87
- # less_than_or_equal_to options.
88
- #
89
- def more_than_maximum?
90
- @maximum_values.each do |key, value|
91
- return false, :count => value unless bad?(value + 1, default_message_for(key))
92
- end
93
- true
94
- end
95
-
96
- # Check less_than_minimum? for equal_to, more_than and
97
- # more_than_or_equal_to options.
98
- #
99
- def less_than_minimum?
100
- @minimum_values.each do |key, value|
101
- return false, :count => value unless bad?(value - 1, default_message_for(key))
102
- end
103
- true
104
- end
105
-
106
- # Returns a valid value for test.
107
- #
108
- def valid_value_for_test
109
- value = @options[:equal_to] || @options[:less_than_or_equal_to] || @options[:greater_than_or_equal_to]
110
-
111
- value ||= @options[:less_than] - 1 if @options[:less_than]
112
- value ||= @options[:greater_than] + 1 if @options[:greater_than]
113
-
114
- value ||= 10
115
-
116
- if @options[:even]
117
- value = (value / 2) * 2
118
- elsif @options[:odd]
119
- value = ((value / 2) * 2) + 1
120
- end
121
-
122
- value
123
- end
124
-
125
- # Returns a valid even value for test.
126
- # The method valid_value_for_test checks for :even option but does not
127
- # return necessarily an even value
128
- #
129
- def even_valid_value_for_test
130
- (valid_value_for_test / 2) * 2
131
- end
132
-
133
- # Returns the default message for each key (:odd, :even, :equal_to, ...).
134
- # If the user provided a message, we use it, otherwise we should use
135
- # the given key as message.
136
- #
137
- # For example, a default_message_for(:odd), if none is provided, will be
138
- # :odd. So we have create :odd_message in the options hash, that when
139
- # called later, will return :odd.
140
- #
141
- def default_message_for(key)
142
- if @options[:message]
143
- :message
144
- else
145
- @options[:"#{key}_message"] = key
146
- :"#{key}_message"
147
- end
148
- end
149
- end
150
-
151
- # Ensures that the given attributes accepts only numbers.
152
- #
153
- # == Options
154
- #
155
- # * <tt>:only_integer</tt> - when supplied, checks if it accepts only integers or not
156
- # * <tt>:odd</tt> - when supplied, checks if it accepts only odd values or not
157
- # * <tt>:even</tt> - when supplied, checks if it accepts only even values or not
158
- # * <tt>:equal_to</tt> - when supplied, checks if attributes are only valid when equal to given value
159
- # * <tt>:less_than</tt> - when supplied, checks if attributes are only valid when less than given value
160
- # * <tt>:greater_than</tt> - when supplied, checks if attributes are only valid when greater than given value
161
- # * <tt>:less_than_or_equal_to</tt> - when supplied, checks if attributes are only valid when less than or equal to given value
162
- # * <tt>:greater_than_or_equal_to</tt> - when supplied, checks if attributes are only valid when greater than or equal to given value
163
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
164
- # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.not_a_number')</tt>
165
- #
166
- # == Examples
167
- #
168
- # it { should validate_numericality_of(:age).odd }
169
- # it { should validate_numericality_of(:age).even }
170
- # it { should validate_numericality_of(:age).only_integer }
171
- # it { should validate_numericality_of(:age, :odd => true) }
172
- # it { should validate_numericality_of(:age, :even => true) }
1
+ module Remarkable
2
+ module ActiveRecord
3
+ module Matchers
4
+ class ValidateNumericalityOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
+ arguments :collection => :attributes, :as => :attribute
6
+
7
+ optional :equal_to, :greater_than_or_equal_to, :greater_than,
8
+ :less_than_or_equal_to, :less_than, :message
9
+
10
+ optional :only_integer, :odd, :even, :allow_nil, :allow_blank, :default => true
11
+
12
+ collection_assertions :only_numeric_values?, :allow_blank?, :allow_nil?,
13
+ :only_integer?, :only_odd?, :only_even?, :equals_to?,
14
+ :less_than_minimum?, :more_than_maximum?
15
+
16
+ # Before assertions, we rearrange the values.
17
+ #
18
+ # Notice that :less_than gives a maximum value while :more_than given
19
+ # a minimum value. While :equal_to generate both.
20
+ #
21
+ before_assert do
22
+ @maximum_values = {}
23
+ @minimum_values = {}
24
+
25
+ if value = @options[:equal_to]
26
+ @maximum_values[:equal_to] = value
27
+ @minimum_values[:equal_to] = value
28
+ elsif value = @options[:less_than]
29
+ @maximum_values[:less_than] = value - 1
30
+ elsif value = @options[:greater_than]
31
+ @minimum_values[:greater_than] = value + 1
32
+ elsif value = @options[:less_than_or_equal_to]
33
+ @maximum_values[:less_than_or_equal_to] = value
34
+ elsif value = @options[:greater_than_or_equal_to]
35
+ @minimum_values[:greater_than_or_equal_to] = value
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def allow_nil?
42
+ super(default_message_for(:not_a_number))
43
+ end
44
+
45
+ def allow_blank?
46
+ super(default_message_for(:not_a_number))
47
+ end
48
+
49
+ def only_numeric_values?
50
+ bad?("abcd", default_message_for(:not_a_number))
51
+ end
52
+
53
+ def only_integer?
54
+ assert_bad_or_good_if_key(:only_integer, valid_value_for_test.to_f, default_message_for(:not_a_number))
55
+ end
56
+
57
+ # In ActiveRecord, when we supply :even, does not matter the value, it
58
+ # considers that should even values should be accepted.
59
+ #
60
+ def only_even?
61
+ return true unless @options[:even]
62
+ bad?(even_valid_value_for_test + 1, default_message_for(:even))
63
+ end
64
+
65
+ # In ActiveRecord, when we supply :odd, does not matter the value, it
66
+ # considers that should odd values should be accepted.
67
+ #
68
+ def only_odd?
69
+ return true unless @options[:odd]
70
+ bad?(even_valid_value_for_test, default_message_for(:odd))
71
+ end
72
+
73
+ # Check equal_to for all registered values.
74
+ #
75
+ def equals_to?
76
+ values = {}
77
+ @maximum_values.each { |k, v| values[k] = v }
78
+ @minimum_values.each { |k, v| values[k] = v }
79
+
80
+ values.each do |key, value|
81
+ return false, :count => value unless good?(value, default_message_for(key))
82
+ end
83
+ true
84
+ end
85
+
86
+ # Check more_than_maximum? for equal_to, less_than and
87
+ # less_than_or_equal_to options.
88
+ #
89
+ def more_than_maximum?
90
+ @maximum_values.each do |key, value|
91
+ return false, :count => value unless bad?(value + 1, default_message_for(key))
92
+ end
93
+ true
94
+ end
95
+
96
+ # Check less_than_minimum? for equal_to, more_than and
97
+ # more_than_or_equal_to options.
98
+ #
99
+ def less_than_minimum?
100
+ @minimum_values.each do |key, value|
101
+ return false, :count => value unless bad?(value - 1, default_message_for(key))
102
+ end
103
+ true
104
+ end
105
+
106
+ # Returns a valid value for test.
107
+ #
108
+ def valid_value_for_test
109
+ value = @options[:equal_to] || @options[:less_than_or_equal_to] || @options[:greater_than_or_equal_to]
110
+
111
+ value ||= @options[:less_than] - 1 if @options[:less_than]
112
+ value ||= @options[:greater_than] + 1 if @options[:greater_than]
113
+
114
+ value ||= 10
115
+
116
+ if @options[:even]
117
+ value = (value / 2) * 2
118
+ elsif @options[:odd]
119
+ value = ((value / 2) * 2) + 1
120
+ end
121
+
122
+ value
123
+ end
124
+
125
+ # Returns a valid even value for test.
126
+ # The method valid_value_for_test checks for :even option but does not
127
+ # return necessarily an even value
128
+ #
129
+ def even_valid_value_for_test
130
+ (valid_value_for_test / 2) * 2
131
+ end
132
+
133
+ # Returns the default message for each key (:odd, :even, :equal_to, ...).
134
+ # If the user provided a message, we use it, otherwise we should use
135
+ # the given key as message.
136
+ #
137
+ # For example, a default_message_for(:odd), if none is provided, will be
138
+ # :odd. So we have create :odd_message in the options hash, that when
139
+ # called later, will return :odd.
140
+ #
141
+ def default_message_for(key)
142
+ if @options[:message]
143
+ :message
144
+ else
145
+ @options[:"#{key}_message"] = key
146
+ :"#{key}_message"
147
+ end
148
+ end
149
+ end
150
+
151
+ # Ensures that the given attributes accepts only numbers.
173
152
  #
174
- # should_validate_numericality_of :age, :price
153
+ # == Options
154
+ #
155
+ # * <tt>:only_integer</tt> - when supplied, checks if it accepts only integers or not
156
+ # * <tt>:odd</tt> - when supplied, checks if it accepts only odd values or not
157
+ # * <tt>:even</tt> - when supplied, checks if it accepts only even values or not
158
+ # * <tt>:equal_to</tt> - when supplied, checks if attributes are only valid when equal to given value
159
+ # * <tt>:less_than</tt> - when supplied, checks if attributes are only valid when less than given value
160
+ # * <tt>:greater_than</tt> - when supplied, checks if attributes are only valid when greater than given value
161
+ # * <tt>:less_than_or_equal_to</tt> - when supplied, checks if attributes are only valid when less than or equal to given value
162
+ # * <tt>:greater_than_or_equal_to</tt> - when supplied, checks if attributes are only valid when greater than or equal to given value
163
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
164
+ # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.not_a_number')</tt>
165
+ #
166
+ # == Examples
167
+ #
168
+ # it { should validate_numericality_of(:age).odd }
169
+ # it { should validate_numericality_of(:age).even }
170
+ # it { should validate_numericality_of(:age).only_integer }
171
+ # it { should validate_numericality_of(:age, :odd => true) }
172
+ # it { should validate_numericality_of(:age, :even => true) }
173
+ #
174
+ # should_validate_numericality_of :age, :price
175
175
  # should_validate_numericality_of :price, :only_integer => false, :greater_than => 10
176
176
  #
177
177
  # should_validate_numericality_of :price do |m|
178
178
  # m.only_integer = false
179
179
  # m.greater_than = 10
180
180
  # end
181
- #
182
- def validate_numericality_of(*attributes, &block)
183
- ValidateNumericalityOfMatcher.new(*attributes, &block).spec(self)
184
- end
185
-
186
- end
187
- end
188
- end
181
+ #
182
+ def validate_numericality_of(*attributes, &block)
183
+ ValidateNumericalityOfMatcher.new(*attributes, &block).spec(self)
184
+ end
185
+
186
+ end
187
+ end
188
+ end