-
-
Notifications
You must be signed in to change notification settings - Fork 912
/
ensure_length_of_matcher.rb
176 lines (154 loc) · 5.62 KB
/
ensure_length_of_matcher.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
module Shoulda # :nodoc:
module Matchers
module ActiveModel # :nodoc:
# Ensures that the length of the attribute is validated. Only works with
# string/text columns because it uses a string to check length.
#
# Options:
# * <tt>is_at_least</tt> - minimum length of this attribute
# * <tt>is_at_most</tt> - maximum length of this attribute
# * <tt>is_equal_to</tt> - exact requred length of this attribute
# * <tt>with_short_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
# translation for :too_short.
# * <tt>with_long_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
# translation for :too_long.
# * <tt>with_message</tt> - value the test expects to find in
# <tt>errors.on(:attribute)</tt>. Regexp or string. Defaults to the
# translation for :wrong_length. Used in conjunction with
# <tt>is_equal_to</tt>.
#
# Examples:
# it { should ensure_length_of(:password).
# is_at_least(6).
# is_at_most(20) }
# it { should ensure_length_of(:name).
# is_at_least(3).
# with_short_message(/not long enough/) }
# it { should ensure_length_of(:ssn).
# is_equal_to(9).
# with_message(/is invalid/) }
def ensure_length_of(attr)
EnsureLengthOfMatcher.new(attr)
end
class EnsureLengthOfMatcher < ValidationMatcher # :nodoc:
include Helpers
def initialize(attribute)
super(attribute)
@options = {}
end
def is_at_least(length)
@options[:minimum] = length
@short_message ||= :too_short
self
end
def is_at_most(length)
@options[:maximum] = length
@long_message ||= :too_long
self
end
def is_equal_to(length)
@options[:minimum] = length
@options[:maximum] = length
@short_message ||= :wrong_length
@long_message ||= :wrong_length
self
end
def with_short_message(message)
if message
@short_message = message
end
self
end
alias_method :with_message, :with_short_message
def with_long_message(message)
if message
@long_message = message
end
self
end
def description
description = "ensure #{@attribute} has a length "
if @options.key?(:minimum) && @options.key?(:maximum)
if @options[:minimum] == @options[:maximum]
description << "of exactly #{@options[:minimum]}"
else
description << "between #{@options[:minimum]} and #{@options[:maximum]}"
end
else
description << "of at least #{@options[:minimum]}" if @options[:minimum]
description << "of at most #{@options[:maximum]}" if @options[:maximum]
end
description
end
def matches?(subject)
super(subject)
translate_messages!
lower_bound_matches? && upper_bound_matches?
end
private
def translate_messages!
if Symbol === @short_message
@short_message = default_error_message(@short_message,
:model_name => @subject.class.to_s.underscore,
:instance => @subject,
:attribute => @attribute,
:count => @options[:minimum])
end
if Symbol === @long_message
@long_message = default_error_message(@long_message,
:model_name => @subject.class.to_s.underscore,
:instance => @subject,
:attribute => @attribute,
:count => @options[:maximum])
end
end
def lower_bound_matches?
disallows_lower_length? && allows_minimum_length?
end
def upper_bound_matches?
disallows_higher_length? && allows_maximum_length?
end
def disallows_lower_length?
if @options.key?(:minimum)
@options[:minimum] == 0 ||
disallows_length_of?(@options[:minimum] - 1, @short_message)
else
true
end
end
def disallows_higher_length?
if @options.key?(:maximum)
disallows_length_of?(@options[:maximum] + 1, @long_message)
else
true
end
end
def allows_minimum_length?
if @options.key?(:minimum)
allows_length_of?(@options[:minimum], @short_message)
else
true
end
end
def allows_maximum_length?
if @options.key?(:maximum)
allows_length_of?(@options[:maximum], @long_message)
else
true
end
end
def allows_length_of?(length, message)
allows_value_of(string_of_length(length), message)
end
def disallows_length_of?(length, message)
disallows_value_of(string_of_length(length), message)
end
def string_of_length(length)
'x' * length
end
end
end
end
end