shoulda-matchers 1.0.0.beta1
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.
- data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +116 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +70 -0
- data/Rakefile +50 -0
- data/lib/shoulda-matchers.rb +8 -0
- data/lib/shoulda/matchers/action_controller.rb +38 -0
- data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +114 -0
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +50 -0
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +62 -0
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +54 -0
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +99 -0
- data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +74 -0
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +85 -0
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +93 -0
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +98 -0
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +94 -0
- data/lib/shoulda/matchers/action_mailer.rb +22 -0
- data/lib/shoulda/matchers/action_mailer/have_sent_email.rb +115 -0
- data/lib/shoulda/matchers/active_record.rb +42 -0
- data/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb +83 -0
- data/lib/shoulda/matchers/active_record/allow_value_matcher.rb +110 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +226 -0
- data/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +169 -0
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +112 -0
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +59 -0
- data/lib/shoulda/matchers/active_record/helpers.rb +34 -0
- data/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb +65 -0
- data/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/matchers/active_record/validation_matcher.rb +56 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +23 -0
- data/lib/shoulda/matchers/integrations/test_unit.rb +41 -0
- data/lib/shoulda/matchers/version.rb +5 -0
- metadata +113 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
|
5
|
+
# Ensures that the attribute can be set to the given value.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# * <tt>with_message</tt> - value the test expects to find in
|
9
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. If omitted,
|
10
|
+
# the test looks for any errors in <tt>errors.on(:attribute)</tt>.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# it { should_not allow_value('bad').for(:isbn) }
|
14
|
+
# it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
|
15
|
+
#
|
16
|
+
def allow_value(value)
|
17
|
+
AllowValueMatcher.new(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
class AllowValueMatcher # :nodoc:
|
21
|
+
include Helpers
|
22
|
+
|
23
|
+
def initialize(value)
|
24
|
+
@value = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def for(attribute)
|
28
|
+
@attribute = attribute
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_message(message)
|
33
|
+
@expected_message = message if message
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def matches?(instance)
|
38
|
+
@instance = instance
|
39
|
+
if Symbol === @expected_message
|
40
|
+
@expected_message = default_error_message(@expected_message)
|
41
|
+
end
|
42
|
+
@instance.send("#{@attribute}=", @value)
|
43
|
+
!errors_match?
|
44
|
+
end
|
45
|
+
|
46
|
+
def failure_message
|
47
|
+
"Did not expect #{expectation}, got error: #{@matched_error}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def negative_failure_message
|
51
|
+
"Expected #{expectation}, got #{error_description}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def description
|
55
|
+
"allow #{@attribute} to be set to #{@value.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def errors_match?
|
61
|
+
@instance.valid?
|
62
|
+
@errors = errors_for_attribute(@instance, @attribute)
|
63
|
+
@errors = [@errors] unless @errors.is_a?(Array)
|
64
|
+
@expected_message ? (errors_match_regexp? || errors_match_string?) : (@errors.compact.any?)
|
65
|
+
end
|
66
|
+
|
67
|
+
def errors_for_attribute(instance, attribute)
|
68
|
+
if instance.errors.respond_to?(:[])
|
69
|
+
instance.errors[attribute]
|
70
|
+
else
|
71
|
+
instance.errors.on(attribute)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def errors_match_regexp?
|
76
|
+
if Regexp === @expected_message
|
77
|
+
@matched_error = @errors.detect { |e| e =~ @expected_message }
|
78
|
+
!@matched_error.nil?
|
79
|
+
else
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def errors_match_string?
|
85
|
+
if @errors.include?(@expected_message)
|
86
|
+
@matched_error = @expected_message
|
87
|
+
true
|
88
|
+
else
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def expectation
|
94
|
+
"errors " <<
|
95
|
+
(@expected_message ? "to include #{@expected_message.inspect} " : "") <<
|
96
|
+
"when #{@attribute} is set to #{@value.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def error_description
|
100
|
+
if @instance.errors.empty?
|
101
|
+
"no errors"
|
102
|
+
else
|
103
|
+
"errors: #{pretty_error_messages(@instance)}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
|
5
|
+
# Ensure that the belongs_to relationship exists.
|
6
|
+
#
|
7
|
+
# it { should belong_to(:parent) }
|
8
|
+
#
|
9
|
+
def belong_to(name)
|
10
|
+
AssociationMatcher.new(:belongs_to, name)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Ensures that the has_many relationship exists. Will also test that the
|
14
|
+
# associated table has the required columns. Works with polymorphic
|
15
|
+
# associations.
|
16
|
+
#
|
17
|
+
# Options:
|
18
|
+
# * <tt>through</tt> - association name for <tt>has_many :through</tt>
|
19
|
+
# * <tt>dependent</tt> - tests that the association makes use of the
|
20
|
+
# dependent option.
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# it { should have_many(:friends) }
|
24
|
+
# it { should have_many(:enemies).through(:friends) }
|
25
|
+
# it { should have_many(:enemies).dependent(:destroy) }
|
26
|
+
#
|
27
|
+
def have_many(name)
|
28
|
+
AssociationMatcher.new(:has_many, name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Ensure that the has_one relationship exists. Will also test that the
|
32
|
+
# associated table has the required columns. Works with polymorphic
|
33
|
+
# associations.
|
34
|
+
#
|
35
|
+
# Options:
|
36
|
+
# * <tt>:dependent</tt> - tests that the association makes use of the
|
37
|
+
# dependent option.
|
38
|
+
#
|
39
|
+
# Example:
|
40
|
+
# it { should have_one(:god) } # unless hindu
|
41
|
+
#
|
42
|
+
def have_one(name)
|
43
|
+
AssociationMatcher.new(:has_one, name)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Ensures that the has_and_belongs_to_many relationship exists, and that
|
47
|
+
# the join table is in place.
|
48
|
+
#
|
49
|
+
# it { should have_and_belong_to_many(:posts) }
|
50
|
+
#
|
51
|
+
def have_and_belong_to_many(name)
|
52
|
+
AssociationMatcher.new(:has_and_belongs_to_many, name)
|
53
|
+
end
|
54
|
+
|
55
|
+
class AssociationMatcher # :nodoc:
|
56
|
+
def initialize(macro, name)
|
57
|
+
@macro = macro
|
58
|
+
@name = name
|
59
|
+
end
|
60
|
+
|
61
|
+
def through(through)
|
62
|
+
@through = through
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def dependent(dependent)
|
67
|
+
@dependent = dependent
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def matches?(subject)
|
72
|
+
@subject = subject
|
73
|
+
association_exists? &&
|
74
|
+
macro_correct? &&
|
75
|
+
foreign_key_exists? &&
|
76
|
+
through_association_valid? &&
|
77
|
+
dependent_correct? &&
|
78
|
+
join_table_exists?
|
79
|
+
end
|
80
|
+
|
81
|
+
def failure_message
|
82
|
+
"Expected #{expectation} (#{@missing})"
|
83
|
+
end
|
84
|
+
|
85
|
+
def negative_failure_message
|
86
|
+
"Did not expect #{expectation}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def description
|
90
|
+
description = "#{macro_description} #{@name}"
|
91
|
+
description += " through #{@through}" if @through
|
92
|
+
description += " dependent => #{@dependent}" if @dependent
|
93
|
+
description
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def association_exists?
|
99
|
+
if reflection.nil?
|
100
|
+
@missing = "no association called #{@name}"
|
101
|
+
false
|
102
|
+
else
|
103
|
+
true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def macro_correct?
|
108
|
+
if reflection.macro == @macro
|
109
|
+
true
|
110
|
+
else
|
111
|
+
@missing = "actual association type was #{reflection.macro}"
|
112
|
+
false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def foreign_key_exists?
|
117
|
+
!(belongs_foreign_key_missing? || has_foreign_key_missing?)
|
118
|
+
end
|
119
|
+
|
120
|
+
def belongs_foreign_key_missing?
|
121
|
+
@macro == :belongs_to && !class_has_foreign_key?(model_class)
|
122
|
+
end
|
123
|
+
|
124
|
+
def has_foreign_key_missing?
|
125
|
+
[:has_many, :has_one].include?(@macro) &&
|
126
|
+
!through? &&
|
127
|
+
!class_has_foreign_key?(associated_class)
|
128
|
+
end
|
129
|
+
|
130
|
+
def through_association_valid?
|
131
|
+
@through.nil? || (through_association_exists? && through_association_correct?)
|
132
|
+
end
|
133
|
+
|
134
|
+
def through_association_exists?
|
135
|
+
if through_reflection.nil?
|
136
|
+
@missing = "#{model_class.name} does not have any relationship to #{@through}"
|
137
|
+
false
|
138
|
+
else
|
139
|
+
true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def through_association_correct?
|
144
|
+
if @through == reflection.options[:through]
|
145
|
+
true
|
146
|
+
else
|
147
|
+
@missing = "Expected #{model_class.name} to have #{@name} through #{@through}, " <<
|
148
|
+
"but got it through #{reflection.options[:through]}"
|
149
|
+
false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def dependent_correct?
|
154
|
+
if @dependent.nil? || @dependent.to_s == reflection.options[:dependent].to_s
|
155
|
+
true
|
156
|
+
else
|
157
|
+
@missing = "#{@name} should have #{@dependent} dependency"
|
158
|
+
false
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def join_table_exists?
|
163
|
+
if @macro != :has_and_belongs_to_many ||
|
164
|
+
::ActiveRecord::Base.connection.tables.include?(join_table.to_s)
|
165
|
+
true
|
166
|
+
else
|
167
|
+
@missing = "join table #{join_table} doesn't exist"
|
168
|
+
false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def class_has_foreign_key?(klass)
|
173
|
+
if klass.column_names.include?(foreign_key.to_s)
|
174
|
+
true
|
175
|
+
else
|
176
|
+
@missing = "#{klass} does not have a #{foreign_key} foreign key."
|
177
|
+
false
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def model_class
|
182
|
+
@subject.class
|
183
|
+
end
|
184
|
+
|
185
|
+
def join_table
|
186
|
+
reflection.options[:join_table]
|
187
|
+
end
|
188
|
+
|
189
|
+
def associated_class
|
190
|
+
reflection.klass
|
191
|
+
end
|
192
|
+
|
193
|
+
def foreign_key
|
194
|
+
reflection.primary_key_name
|
195
|
+
end
|
196
|
+
|
197
|
+
def through?
|
198
|
+
reflection.options[:through]
|
199
|
+
end
|
200
|
+
|
201
|
+
def reflection
|
202
|
+
@reflection ||= model_class.reflect_on_association(@name)
|
203
|
+
end
|
204
|
+
|
205
|
+
def through_reflection
|
206
|
+
@through_reflection ||= model_class.reflect_on_association(@through)
|
207
|
+
end
|
208
|
+
|
209
|
+
def expectation
|
210
|
+
"#{model_class.name} to have a #{@macro} association called #{@name}"
|
211
|
+
end
|
212
|
+
|
213
|
+
def macro_description
|
214
|
+
case @macro.to_s
|
215
|
+
when 'belongs_to' then 'belong to'
|
216
|
+
when 'has_many' then 'have many'
|
217
|
+
when 'has_one' then 'have one'
|
218
|
+
when 'has_and_belongs_to_many' then
|
219
|
+
'have and belong to many'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
|
5
|
+
# Ensure that the attribute's value is in the range specified
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# * <tt>in_range</tt> - the range of allowed values for this attribute
|
9
|
+
# * <tt>with_low_message</tt> - value the test expects to find in
|
10
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
11
|
+
# translation for :inclusion.
|
12
|
+
# * <tt>with_high_message</tt> - value the test expects to find in
|
13
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
14
|
+
# translation for :inclusion.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
# it { should ensure_inclusion_of(:age).in_range(0..100) }
|
18
|
+
#
|
19
|
+
def ensure_inclusion_of(attr)
|
20
|
+
EnsureInclusionOfMatcher.new(attr)
|
21
|
+
end
|
22
|
+
|
23
|
+
class EnsureInclusionOfMatcher < ValidationMatcher # :nodoc:
|
24
|
+
|
25
|
+
def in_range(range)
|
26
|
+
@range = range
|
27
|
+
@minimum = range.first
|
28
|
+
@maximum = range.last
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_message(message)
|
33
|
+
if message
|
34
|
+
@low_message = message
|
35
|
+
@high_message = message
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_low_message(message)
|
41
|
+
@low_message = message if message
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_high_message(message)
|
46
|
+
@high_message = message if message
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def description
|
51
|
+
"ensure inclusion of #{@attribute} in #{@range.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def matches?(subject)
|
55
|
+
super(subject)
|
56
|
+
|
57
|
+
@low_message ||= :inclusion
|
58
|
+
@high_message ||= :inclusion
|
59
|
+
|
60
|
+
disallows_lower_value &&
|
61
|
+
allows_minimum_value &&
|
62
|
+
disallows_higher_value &&
|
63
|
+
allows_maximum_value
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def disallows_lower_value
|
69
|
+
@minimum == 0 || disallows_value_of(@minimum - 1, @low_message)
|
70
|
+
end
|
71
|
+
|
72
|
+
def disallows_higher_value
|
73
|
+
disallows_value_of(@maximum + 1, @high_message)
|
74
|
+
end
|
75
|
+
|
76
|
+
def allows_minimum_value
|
77
|
+
allows_value_of(@minimum, @low_message)
|
78
|
+
end
|
79
|
+
|
80
|
+
def allows_maximum_value
|
81
|
+
allows_value_of(@maximum, @high_message)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Shoulda # :nodoc:
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
|
5
|
+
# Ensures that the length of the attribute is validated.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# * <tt>is_at_least</tt> - minimum length of this attribute
|
9
|
+
# * <tt>is_at_most</tt> - maximum length of this attribute
|
10
|
+
# * <tt>is_equal_to</tt> - exact requred length of this attribute
|
11
|
+
# * <tt>with_short_message</tt> - value the test expects to find in
|
12
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
13
|
+
# translation for :too_short.
|
14
|
+
# * <tt>with_long_message</tt> - value the test expects to find in
|
15
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
16
|
+
# translation for :too_long.
|
17
|
+
# * <tt>with_message</tt> - value the test expects to find in
|
18
|
+
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
|
19
|
+
# translation for :wrong_length. Used in conjunction with
|
20
|
+
# <tt>is_equal_to</tt>.
|
21
|
+
#
|
22
|
+
# Examples:
|
23
|
+
# it { should ensure_length_of(:password).
|
24
|
+
# is_at_least(6).
|
25
|
+
# is_at_most(20) }
|
26
|
+
# it { should ensure_length_of(:name).
|
27
|
+
# is_at_least(3).
|
28
|
+
# with_short_message(/not long enough/) }
|
29
|
+
# it { should ensure_length_of(:ssn).
|
30
|
+
# is_equal_to(9).
|
31
|
+
# with_message(/is invalid/) }
|
32
|
+
def ensure_length_of(attr)
|
33
|
+
EnsureLengthOfMatcher.new(attr)
|
34
|
+
end
|
35
|
+
|
36
|
+
class EnsureLengthOfMatcher < ValidationMatcher # :nodoc:
|
37
|
+
include Helpers
|
38
|
+
|
39
|
+
def is_at_least(length)
|
40
|
+
@minimum = length
|
41
|
+
@short_message ||= :too_short
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def is_at_most(length)
|
46
|
+
@maximum = length
|
47
|
+
@long_message ||= :too_long
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def is_equal_to(length)
|
52
|
+
@minimum = length
|
53
|
+
@maximum = length
|
54
|
+
@short_message ||= :wrong_length
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_short_message(message)
|
59
|
+
@short_message = message if message
|
60
|
+
self
|
61
|
+
end
|
62
|
+
alias_method :with_message, :with_short_message
|
63
|
+
|
64
|
+
def with_long_message(message)
|
65
|
+
@long_message = message if message
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def description
|
70
|
+
description = "ensure #{@attribute} has a length "
|
71
|
+
if @minimum && @maximum
|
72
|
+
if @minimum == @maximum
|
73
|
+
description << "of exactly #{@minimum}"
|
74
|
+
else
|
75
|
+
description << "between #{@minimum} and #{@maximum}"
|
76
|
+
end
|
77
|
+
else
|
78
|
+
description << "of at least #{@minimum}" if @minimum
|
79
|
+
description << "of at most #{@maximum}" if @maximum
|
80
|
+
end
|
81
|
+
description
|
82
|
+
end
|
83
|
+
|
84
|
+
def matches?(subject)
|
85
|
+
super(subject)
|
86
|
+
translate_messages!
|
87
|
+
disallows_lower_length &&
|
88
|
+
allows_minimum_length &&
|
89
|
+
((@minimum == @maximum) ||
|
90
|
+
(disallows_higher_length &&
|
91
|
+
allows_maximum_length))
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def translate_messages!
|
97
|
+
if Symbol === @short_message
|
98
|
+
@short_message = default_error_message(@short_message,
|
99
|
+
:count => @minimum)
|
100
|
+
end
|
101
|
+
|
102
|
+
if Symbol === @long_message
|
103
|
+
@long_message = default_error_message(@long_message,
|
104
|
+
:count => @maximum)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def disallows_lower_length
|
109
|
+
@minimum == 0 ||
|
110
|
+
@minimum.nil? ||
|
111
|
+
disallows_length_of(@minimum - 1, @short_message)
|
112
|
+
end
|
113
|
+
|
114
|
+
def disallows_higher_length
|
115
|
+
@maximum.nil? || disallows_length_of(@maximum + 1, @long_message)
|
116
|
+
end
|
117
|
+
|
118
|
+
def allows_minimum_length
|
119
|
+
allows_length_of(@minimum, @short_message)
|
120
|
+
end
|
121
|
+
|
122
|
+
def allows_maximum_length
|
123
|
+
allows_length_of(@maximum, @long_message)
|
124
|
+
end
|
125
|
+
|
126
|
+
def allows_length_of(length, message)
|
127
|
+
length.nil? || allows_value_of(string_of_length(length), message)
|
128
|
+
end
|
129
|
+
|
130
|
+
def disallows_length_of(length, message)
|
131
|
+
length.nil? || disallows_value_of(string_of_length(length), message)
|
132
|
+
end
|
133
|
+
|
134
|
+
def string_of_length(length)
|
135
|
+
'x' * length
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|