remarkable_activerecord 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +47 -0
- data/LICENSE +20 -0
- data/README +2 -0
- data/lib/remarkable_activerecord/base.rb +238 -0
- data/lib/remarkable_activerecord/human_names.rb +37 -0
- data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +34 -0
- data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +94 -0
- data/lib/remarkable_activerecord/matchers/association_matcher.rb +235 -0
- data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +68 -0
- data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +57 -0
- data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +30 -0
- data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +80 -0
- data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +51 -0
- data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +99 -0
- data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +45 -0
- data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +47 -0
- data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +47 -0
- data/lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb +123 -0
- data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +184 -0
- data/lib/remarkable_activerecord/matchers/validate_presence_of_matcher.rb +29 -0
- data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +151 -0
- data/lib/remarkable_activerecord.rb +29 -0
- data/locale/en.yml +253 -0
- data/spec/allow_mass_assignment_of_matcher_spec.rb +57 -0
- data/spec/allow_values_for_matcher_spec.rb +56 -0
- data/spec/association_matcher_spec.rb +616 -0
- data/spec/have_column_matcher_spec.rb +73 -0
- data/spec/have_index_matcher_spec.rb +68 -0
- data/spec/have_readonly_attributes_matcher_spec.rb +47 -0
- data/spec/have_scope_matcher_spec.rb +69 -0
- data/spec/model_builder.rb +101 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/validate_acceptance_of_matcher_spec.rb +68 -0
- data/spec/validate_associated_matcher_spec.rb +122 -0
- data/spec/validate_confirmation_of_matcher_spec.rb +58 -0
- data/spec/validate_exclusion_of_matcher_spec.rb +88 -0
- data/spec/validate_inclusion_of_matcher_spec.rb +84 -0
- data/spec/validate_length_of_matcher_spec.rb +165 -0
- data/spec/validate_numericality_of_matcher_spec.rb +180 -0
- data/spec/validate_presence_of_matcher_spec.rb +52 -0
- data/spec/validate_uniqueness_of_matcher_spec.rb +150 -0
- metadata +112 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# v3.0.0
|
2
|
+
|
3
|
+
[ENHANCEMENT] Added more options to associations matcher. Previously it was
|
4
|
+
handling just :dependent and :through options. Now it deals with:
|
5
|
+
|
6
|
+
:through, :class_name, :foreign_key, :dependent, :join_table, :uniq,
|
7
|
+
:readonly, :validate, :autosave, :counter_cache, :polymorphic
|
8
|
+
|
9
|
+
And they are much smarter! In :join_table and :through cases, they also test if
|
10
|
+
the table exists or not. :counter_cache and :foreign_key also checks if the
|
11
|
+
column exists or not.
|
12
|
+
|
13
|
+
[COMPATIBILITY] Removed callback, have_instance_method and have_class_method
|
14
|
+
matchers. They don't lead to a good TDD since you should test they behavior
|
15
|
+
and not wether they exist or not.
|
16
|
+
|
17
|
+
[COMPATIBILITY] ActiveRecord matches does not pick the instance variable from
|
18
|
+
the spec environment. So we should target only rspec versions that supports
|
19
|
+
subjects (>= 1.1.12).
|
20
|
+
|
21
|
+
Previously, when we are doing this:
|
22
|
+
|
23
|
+
describe Product
|
24
|
+
before(:each){ @product = Product.new(:tangible => true) }
|
25
|
+
should_validate_presence_of :size
|
26
|
+
end
|
27
|
+
|
28
|
+
It was validating the @product instance variable. However this might be not
|
29
|
+
clear. The right way to do that (with subjects) is:
|
30
|
+
|
31
|
+
describe Product
|
32
|
+
subject{ Product.new(:tangible => true) }
|
33
|
+
should_validate_presence_of :size
|
34
|
+
end
|
35
|
+
|
36
|
+
Is also valid to remember that previous versions of Remarkable were overriding
|
37
|
+
subject definitions on rspec. This was also fixed.
|
38
|
+
|
39
|
+
# v2.x
|
40
|
+
|
41
|
+
[ENHANCEMENT] Added associations, allow_mass_assignment, allow_values_for,
|
42
|
+
have_column, have_index, have_scope, have_readonly_attributes,
|
43
|
+
validate_acceptance_of, validate_associate, validate_confirmation_of,
|
44
|
+
validate_exclusion_of, validate_inclusion_of, validate_length_of,
|
45
|
+
validate_numericality_of, validate_presence_of and validate_uniqueness_of
|
46
|
+
matchers.
|
47
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Carlos Brando
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
class Base < Remarkable::Base
|
4
|
+
|
5
|
+
def with_options(opts={})
|
6
|
+
@options.merge!(opts)
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
# Checks for the given key in @options, if it exists and it's true,
|
13
|
+
# tests that the value is bad, otherwise tests that the value is good.
|
14
|
+
#
|
15
|
+
# It accepts the key to check for, the value that is used for testing
|
16
|
+
# and an @options key where the message to search for is.
|
17
|
+
#
|
18
|
+
def assert_bad_or_good_if_key(key, value, message_key=:message) #:nodoc:
|
19
|
+
return true unless @options.key?(key)
|
20
|
+
|
21
|
+
if @options[key]
|
22
|
+
return true if bad?(value, message_key)
|
23
|
+
return false, :not => not_word
|
24
|
+
else
|
25
|
+
return true if good?(value, message_key)
|
26
|
+
return false, :not => ''
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Checks for the given key in @options, if it exists and it's true,
|
31
|
+
# tests that the value is good, otherwise tests that the value is bad.
|
32
|
+
#
|
33
|
+
# It accepts the key to check for, the value that is used for testing
|
34
|
+
# and an @options key where the message to search for is.
|
35
|
+
#
|
36
|
+
def assert_good_or_bad_if_key(key, value, message_key=:message) #:nodoc:
|
37
|
+
return true unless @options.key?(key)
|
38
|
+
|
39
|
+
if @options[key]
|
40
|
+
return true if good?(value, message_key)
|
41
|
+
return false, :not => ''
|
42
|
+
else
|
43
|
+
return true if bad?(value, message_key)
|
44
|
+
return false, :not => not_word
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Default allow_nil? validation. It accepts the message_key which is
|
49
|
+
# the key which contain the message in @options.
|
50
|
+
#
|
51
|
+
# It also gets an allow_nil message on remarkable.active_record.allow_nil
|
52
|
+
# to be used as default.
|
53
|
+
#
|
54
|
+
def allow_nil?(message_key=:message) #:nodoc:
|
55
|
+
valid, options = assert_good_or_bad_if_key(:allow_nil, nil, message_key)
|
56
|
+
|
57
|
+
unless valid
|
58
|
+
default = Remarkable.t "remarkable.active_record.allow_nil", default_i18n_options.except(:scope).merge(options)
|
59
|
+
return false, options.merge(:default => default)
|
60
|
+
end
|
61
|
+
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
# Default allow_blank? validation. It accepts the message_key which is
|
66
|
+
# the key which contain the message in @options.
|
67
|
+
#
|
68
|
+
# It also gets an allow_blank message on remarkable.active_record.allow_blank
|
69
|
+
# to be used as default.
|
70
|
+
#
|
71
|
+
def allow_blank?(message_key=:message) #:nodoc:
|
72
|
+
valid, options = assert_good_or_bad_if_key(:allow_blank, '', message_key)
|
73
|
+
|
74
|
+
unless valid
|
75
|
+
default = Remarkable.t "remarkable.active_record.allow_blank", default_i18n_options.except(:scope).merge(options)
|
76
|
+
return false, options.merge(:default => default)
|
77
|
+
end
|
78
|
+
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
# Shortcut for assert_good_value.
|
83
|
+
#
|
84
|
+
def good?(value, message_sym=:message) #:nodoc:
|
85
|
+
assert_good_value(@subject, @attribute, value, @options[message_sym])
|
86
|
+
end
|
87
|
+
|
88
|
+
# Shortcut for assert_bad_value.
|
89
|
+
#
|
90
|
+
def bad?(value, message_sym=:message) #:nodoc:
|
91
|
+
assert_bad_value(@subject, @attribute, value, @options[message_sym])
|
92
|
+
end
|
93
|
+
|
94
|
+
# Asserts that an Active Record model validates with the passed
|
95
|
+
# <tt>value</tt> by making sure the <tt>error_message_to_avoid</tt> is not
|
96
|
+
# contained within the list of errors for that attribute.
|
97
|
+
#
|
98
|
+
# assert_good_value(User.new, :email, "user@example.com")
|
99
|
+
# assert_good_value(User.new, :ssn, "123456789", /length/)
|
100
|
+
#
|
101
|
+
# If a class is passed as the first argument, a new object will be
|
102
|
+
# instantiated before the assertion. If an instance variable exists with
|
103
|
+
# the same name as the class (underscored), that object will be used
|
104
|
+
# instead.
|
105
|
+
#
|
106
|
+
# assert_good_value(User, :email, "user@example.com")
|
107
|
+
#
|
108
|
+
# @product = Product.new(:tangible => false)
|
109
|
+
# assert_good_value(Product, :price, "0")
|
110
|
+
#
|
111
|
+
def assert_good_value(model, attribute, value, error_message_to_avoid=//) # :nodoc:
|
112
|
+
model.send("#{attribute}=", value)
|
113
|
+
|
114
|
+
return true if model.valid?
|
115
|
+
|
116
|
+
error_message_to_avoid = error_message_from_model(model, attribute, error_message_to_avoid)
|
117
|
+
assert_does_not_contain(model.errors.on(attribute), error_message_to_avoid)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Asserts that an Active Record model invalidates the passed
|
121
|
+
# <tt>value</tt> by making sure the <tt>error_message_to_expect</tt> is
|
122
|
+
# contained within the list of errors for that attribute.
|
123
|
+
#
|
124
|
+
# assert_bad_value(User.new, :email, "invalid")
|
125
|
+
# assert_bad_value(User.new, :ssn, "123", /length/)
|
126
|
+
#
|
127
|
+
# If a class is passed as the first argument, a new object will be
|
128
|
+
# instantiated before the assertion. If an instance variable exists with
|
129
|
+
# the same name as the class (underscored), that object will be used
|
130
|
+
# instead.
|
131
|
+
#
|
132
|
+
# assert_bad_value(User, :email, "invalid")
|
133
|
+
#
|
134
|
+
# @product = Product.new(:tangible => true)
|
135
|
+
# assert_bad_value(Product, :price, "0")
|
136
|
+
#
|
137
|
+
def assert_bad_value(model, attribute, value, error_message_to_expect=:invalid) #:nodoc:
|
138
|
+
model.send("#{attribute}=", value)
|
139
|
+
|
140
|
+
return false if model.valid? || model.errors.on(attribute).blank?
|
141
|
+
|
142
|
+
error_message_to_expect = error_message_from_model(model, attribute, error_message_to_expect)
|
143
|
+
assert_contains(model.errors.on(attribute), error_message_to_expect)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return the error message to be checked. If the message is not a Symbol
|
147
|
+
# neither a Hash, it returns the own message.
|
148
|
+
#
|
149
|
+
# But the nice thing is that when the message is a Symbol we get the error
|
150
|
+
# messsage from within the model, using already existent structure inside
|
151
|
+
# ActiveRecord.
|
152
|
+
#
|
153
|
+
# This allows a couple things from the user side:
|
154
|
+
#
|
155
|
+
# 1. Specify symbols in their tests:
|
156
|
+
#
|
157
|
+
# should_allow_values_for(:shirt_size, 'S', 'M', 'L', :message => :inclusion)
|
158
|
+
#
|
159
|
+
# As we know, allow_values_for searches for a :invalid message. So if we
|
160
|
+
# were testing a validates_inclusion_of with allow_values_for, previously
|
161
|
+
# we had to do something like this:
|
162
|
+
#
|
163
|
+
# should_allow_values_for(:shirt_size, 'S', 'M', 'L', :message => 'not included in list')
|
164
|
+
#
|
165
|
+
# Now everything gets resumed to a Symbol.
|
166
|
+
#
|
167
|
+
# 2. Do not worry with specs if their are using I18n API properly.
|
168
|
+
#
|
169
|
+
# As we know, I18n API provides several interpolation options besides
|
170
|
+
# fallback when creating error messages. If the user changed the message,
|
171
|
+
# macros would start to pass when they shouldn't.
|
172
|
+
#
|
173
|
+
# Using the underlying mechanism inside ActiveRecord makes us free from
|
174
|
+
# all thos errors.
|
175
|
+
#
|
176
|
+
# We replace {{count}} interpolation for 12345 which later is replaced
|
177
|
+
# by a regexp which contains \d+.
|
178
|
+
#
|
179
|
+
def error_message_from_model(model, attribute, message) #:nodoc:
|
180
|
+
if message.is_a? Symbol
|
181
|
+
message = if RAILS_I18N # Rails >= 2.2
|
182
|
+
model.errors.generate_message(attribute, message, :count => '12345')
|
183
|
+
else # Rails <= 2.1
|
184
|
+
::ActiveRecord::Errors.default_error_messages[message] % '12345'
|
185
|
+
end
|
186
|
+
|
187
|
+
if message =~ /12345/
|
188
|
+
message = Regexp.escape(message)
|
189
|
+
message.gsub!('12345', '\d+')
|
190
|
+
message = /#{message}/
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
message
|
195
|
+
end
|
196
|
+
|
197
|
+
# Asserts that the given collection does not contain item x. If x is a
|
198
|
+
# regular expression, ensure that none of the elements from the collection
|
199
|
+
# match x.
|
200
|
+
#
|
201
|
+
def assert_does_not_contain(collection, x) #:nodoc:
|
202
|
+
!assert_contains(collection, x)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Changes how collection are interpolated to provide localized names
|
206
|
+
# whenever is possible.
|
207
|
+
#
|
208
|
+
def collection_interpolation
|
209
|
+
described_class = if @subject
|
210
|
+
subject_class
|
211
|
+
elsif @spec
|
212
|
+
@spec.send(:described_class)
|
213
|
+
end
|
214
|
+
|
215
|
+
if RAILS_I18N && described_class.respond_to?(:human_attribute_name) && self.class.matcher_arguments[:collection]
|
216
|
+
options = {}
|
217
|
+
|
218
|
+
collection_name = self.class.matcher_arguments[:collection].to_sym
|
219
|
+
if collection = instance_variable_get("@#{collection_name}")
|
220
|
+
collection.map!{|attr| described_class.human_attribute_name(attr.to_s, :locale => Remarkable.locale).downcase }
|
221
|
+
options[collection_name] = array_to_sentence(collection)
|
222
|
+
end
|
223
|
+
|
224
|
+
object_name = self.class.matcher_arguments[:as]
|
225
|
+
if object = instance_variable_get("@#{object_name}")
|
226
|
+
object = described_class.human_attribute_name(object.to_s, :locale => Remarkable.locale).downcase
|
227
|
+
options[object_name] = object
|
228
|
+
end
|
229
|
+
|
230
|
+
options
|
231
|
+
else
|
232
|
+
super
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
if defined?(Spec)
|
2
|
+
module Spec
|
3
|
+
module Example
|
4
|
+
module ExampleGroupMethods
|
5
|
+
|
6
|
+
# This allows "describe User" to use the I18n human name of User.
|
7
|
+
#
|
8
|
+
def self.build_description_with_i18n(*args)
|
9
|
+
args.inject("") do |description, arg|
|
10
|
+
arg = if RAILS_I18N && arg.respond_to?(:human_name)
|
11
|
+
arg.human_name(:locale => Remarkable.locale)
|
12
|
+
else
|
13
|
+
arg.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
description << " " unless (description == "" || arg =~ /^(\s|\.|#)/)
|
17
|
+
description << arg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# This is for rspec <= 1.1.12.
|
22
|
+
#
|
23
|
+
def self.description_text(*args)
|
24
|
+
self.build_description_with_i18n(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
# This is for rspec >= 1.2.0.
|
28
|
+
#
|
29
|
+
def build_description_from(*args)
|
30
|
+
text = ExampleGroupMethods.build_description_with_i18n(*args)
|
31
|
+
text == "" ? nil : text
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class AllowMassAssignmentOfMatcher < Remarkable::ActiveRecord::Base
|
5
|
+
arguments :collection => :attributes, :as => :attribute
|
6
|
+
|
7
|
+
collection_assertions :is_protected?, :is_accessible?
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def is_protected?
|
12
|
+
protected = subject_class.protected_attributes || []
|
13
|
+
protected.empty? || !protected.include?(@attribute.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_accessible?
|
17
|
+
accessible = subject_class.accessible_attributes || []
|
18
|
+
accessible.empty? || accessible.include?(@attribute.to_s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Ensures that the attribute can be set on mass update.
|
23
|
+
#
|
24
|
+
# == Examples
|
25
|
+
#
|
26
|
+
# should_allow_mass_assignment_of :email, :name
|
27
|
+
# it { should allow_mass_assignment_of(:email, :name) }
|
28
|
+
#
|
29
|
+
def allow_mass_assignment_of(*attributes)
|
30
|
+
AllowMassAssignmentOfMatcher.new(*attributes).spec(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class AllowValuesForMatcher < Remarkable::ActiveRecord::Base
|
5
|
+
arguments :collection => :attributes, :as => :attribute
|
6
|
+
|
7
|
+
optional :message
|
8
|
+
optional :in, :splat => true
|
9
|
+
optional :allow_nil, :allow_blank, :default => true
|
10
|
+
|
11
|
+
collection_assertions :is_valid?, :is_invalid?, :allow_nil?, :allow_blank?
|
12
|
+
|
13
|
+
default_options :message => :invalid
|
14
|
+
|
15
|
+
before_assert do
|
16
|
+
first_value = @options[:in].is_a?(Array) ? @options[:in].first : @options[:in]
|
17
|
+
@in_range = first_value.is_a?(Range)
|
18
|
+
|
19
|
+
@options[:in] = if @in_range
|
20
|
+
first_value.to_a[0,2] + first_value.to_a[-2,2]
|
21
|
+
else
|
22
|
+
[*@options[:in]].compact
|
23
|
+
end
|
24
|
+
|
25
|
+
@options[:in].uniq!
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def is_valid?
|
31
|
+
valid_values.each do |value|
|
32
|
+
return false, :value => value.inspect unless good?(value)
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_invalid?
|
38
|
+
invalid_values.each do |value|
|
39
|
+
return false, :value => value.inspect unless bad?(value)
|
40
|
+
end
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_values
|
45
|
+
@options[:in]
|
46
|
+
end
|
47
|
+
|
48
|
+
def invalid_values
|
49
|
+
[]
|
50
|
+
end
|
51
|
+
|
52
|
+
def interpolation_options
|
53
|
+
options = if @in_range
|
54
|
+
{ :in => (@options[:in].first..@options[:in].last).inspect }
|
55
|
+
elsif @options[:in].is_a?(Array)
|
56
|
+
{ :in => @options[:in].map(&:inspect).to_sentence }
|
57
|
+
else
|
58
|
+
{ :in => @options[:in].inspect }
|
59
|
+
end
|
60
|
+
|
61
|
+
options.merge!(:behavior => @behavior.to_s)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Ensures that the attribute can be set to the given values.
|
67
|
+
#
|
68
|
+
# Note: this matcher accepts at once just one attribute to test.
|
69
|
+
# Note: this matcher is also aliased as "validate_format_of".
|
70
|
+
#
|
71
|
+
# == Options
|
72
|
+
#
|
73
|
+
# * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
|
74
|
+
# * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
|
75
|
+
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
76
|
+
# Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.invalid')</tt>
|
77
|
+
#
|
78
|
+
# == Examples
|
79
|
+
#
|
80
|
+
# should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
|
81
|
+
# should_not_allow_values_for :isbn, "bad 1", "bad 2"
|
82
|
+
#
|
83
|
+
# it { should allow_values_for(:isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0") }
|
84
|
+
# it { should_not allow_values_for(:isbn, "bad 1", "bad 2") }
|
85
|
+
#
|
86
|
+
def allow_values_for(attribute, *args)
|
87
|
+
options = args.extract_options!
|
88
|
+
AllowValuesForMatcher.new(attribute, options.merge!(:in => args)).spec(self)
|
89
|
+
end
|
90
|
+
alias :validate_format_of :allow_values_for
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|