shoulda-matchers 5.1.0 → 6.4.0
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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +41 -18
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +7 -9
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +46 -1
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
- data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/lib/shoulda/matchers/active_model/qualifiers.rb +1 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -7
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +532 -0
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +5 -5
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +29 -14
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +65 -10
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +76 -86
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +29 -4
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -0
- data/lib/shoulda/matchers/active_model/validator.rb +4 -0
- data/lib/shoulda/matchers/active_model.rb +4 -1
- data/lib/shoulda/matchers/active_record/association_matcher.rb +543 -15
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +34 -4
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +9 -1
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -0
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -0
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +23 -19
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +27 -23
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +338 -30
- data/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +46 -6
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +24 -13
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +3 -5
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- data/lib/shoulda/matchers/active_record/uniqueness/model.rb +13 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +82 -70
- data/lib/shoulda/matchers/active_record.rb +2 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -6
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -6
- data/lib/shoulda/matchers/doublespeak.rb +0 -1
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +13 -15
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +7 -5
- data/lib/shoulda/matchers/integrations/libraries/routing.rb +5 -3
- data/lib/shoulda/matchers/rails_shim.rb +22 -6
- data/lib/shoulda/matchers/util/word_wrap.rb +2 -2
- data/lib/shoulda/matchers/util.rb +18 -20
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers.rb +2 -2
- data/shoulda-matchers.gemspec +2 -2
- metadata +15 -9
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +0 -157
@@ -3,7 +3,7 @@ module Shoulda
|
|
3
3
|
module ActiveModel
|
4
4
|
# The `validate_length_of` matcher tests usage of the
|
5
5
|
# `validates_length_of` matcher. Note that this matcher is intended to be
|
6
|
-
# used against string columns and not integer columns.
|
6
|
+
# used against string columns and associations and not integer columns.
|
7
7
|
#
|
8
8
|
# #### Qualifiers
|
9
9
|
#
|
@@ -36,7 +36,8 @@ module Shoulda
|
|
36
36
|
#
|
37
37
|
# Use `is_at_least` to test usage of the `:minimum` option. This asserts
|
38
38
|
# that the attribute can take a string which is equal to or longer than
|
39
|
-
# the given length and cannot take a string which is shorter.
|
39
|
+
# the given length and cannot take a string which is shorter. This qualifier
|
40
|
+
# also works for associations.
|
40
41
|
#
|
41
42
|
# class User
|
42
43
|
# include ActiveModel::Model
|
@@ -61,7 +62,8 @@ module Shoulda
|
|
61
62
|
#
|
62
63
|
# Use `is_at_most` to test usage of the `:maximum` option. This asserts
|
63
64
|
# that the attribute can take a string which is equal to or shorter than
|
64
|
-
# the given length and cannot take a string which is longer.
|
65
|
+
# the given length and cannot take a string which is longer. This qualifier
|
66
|
+
# also works for associations.
|
65
67
|
#
|
66
68
|
# class User
|
67
69
|
# include ActiveModel::Model
|
@@ -84,7 +86,8 @@ module Shoulda
|
|
84
86
|
#
|
85
87
|
# Use `is_equal_to` to test usage of the `:is` option. This asserts that
|
86
88
|
# the attribute can take a string which is exactly equal to the given
|
87
|
-
# length and cannot take a string which is shorter or longer.
|
89
|
+
# length and cannot take a string which is shorter or longer. This qualifier
|
90
|
+
# also works for associations.
|
88
91
|
#
|
89
92
|
# class User
|
90
93
|
# include ActiveModel::Model
|
@@ -106,7 +109,7 @@ module Shoulda
|
|
106
109
|
# ##### is_at_least + is_at_most
|
107
110
|
#
|
108
111
|
# Use `is_at_least` and `is_at_most` together to test usage of the `:in`
|
109
|
-
# option.
|
112
|
+
# option. This qualifies also works for associations.
|
110
113
|
#
|
111
114
|
# class User
|
112
115
|
# include ActiveModel::Model
|
@@ -239,7 +242,7 @@ module Shoulda
|
|
239
242
|
#
|
240
243
|
# @return [ValidateLengthOfMatcher]
|
241
244
|
#
|
242
|
-
#
|
245
|
+
# ##### allow_blank
|
243
246
|
#
|
244
247
|
# Use `allow_blank` to assert that the attribute allows blank.
|
245
248
|
#
|
@@ -260,6 +263,29 @@ module Shoulda
|
|
260
263
|
# should validate_length_of(:bio).is_at_least(15).allow_blank
|
261
264
|
# end
|
262
265
|
#
|
266
|
+
# ##### as_array
|
267
|
+
#
|
268
|
+
# Use `as_array` if you have an ActiveModel model and the attribute being validated
|
269
|
+
# is designed to store an array. (This is not necessary if you have an ActiveRecord
|
270
|
+
# model with an array column, as the matcher will detect this automatically.)
|
271
|
+
#
|
272
|
+
# class User
|
273
|
+
# include ActiveModel::Model
|
274
|
+
# attribute :arr, array: true
|
275
|
+
#
|
276
|
+
# validates_length_of :arr, minimum: 15
|
277
|
+
# end
|
278
|
+
#
|
279
|
+
# # RSpec
|
280
|
+
# describe User do
|
281
|
+
# it { should validate_length_of(:arr).as_array.is_at_least(15) }
|
282
|
+
# end
|
283
|
+
#
|
284
|
+
# # Minitest (Shoulda)
|
285
|
+
# class UserTest < ActiveSupport::TestCase
|
286
|
+
# should validate_length_of(:arr).as_array.is_at_least(15)
|
287
|
+
# end
|
288
|
+
#
|
263
289
|
def validate_length_of(attr)
|
264
290
|
ValidateLengthOfMatcher.new(attr)
|
265
291
|
end
|
@@ -275,6 +301,11 @@ module Shoulda
|
|
275
301
|
@long_message = nil
|
276
302
|
end
|
277
303
|
|
304
|
+
def as_array
|
305
|
+
@options[:array] = true
|
306
|
+
self
|
307
|
+
end
|
308
|
+
|
278
309
|
def is_at_least(length)
|
279
310
|
@options[:minimum] = length
|
280
311
|
@short_message ||= :too_short
|
@@ -451,15 +482,39 @@ module Shoulda
|
|
451
482
|
end
|
452
483
|
|
453
484
|
def allows_length_of?(length, message)
|
454
|
-
allows_value_of(
|
485
|
+
allows_value_of(value_of_length(length), message)
|
455
486
|
end
|
456
487
|
|
457
488
|
def disallows_length_of?(length, message)
|
458
|
-
disallows_value_of(
|
489
|
+
disallows_value_of(value_of_length(length), message)
|
490
|
+
end
|
491
|
+
|
492
|
+
def value_of_length(length)
|
493
|
+
if array_column?
|
494
|
+
['x'] * length
|
495
|
+
elsif collection_association?
|
496
|
+
Array.new(length) { association_reflection.klass.new }
|
497
|
+
else
|
498
|
+
'x' * length
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
def array_column?
|
503
|
+
@options[:array] || super
|
504
|
+
end
|
505
|
+
|
506
|
+
def collection_association?
|
507
|
+
association? && [:has_many, :has_and_belongs_to_many].include?(
|
508
|
+
association_reflection.macro,
|
509
|
+
)
|
510
|
+
end
|
511
|
+
|
512
|
+
def association?
|
513
|
+
association_reflection.present?
|
459
514
|
end
|
460
515
|
|
461
|
-
def
|
462
|
-
|
516
|
+
def association_reflection
|
517
|
+
model.try(:reflect_on_association, @attribute)
|
463
518
|
end
|
464
519
|
|
465
520
|
def translated_short_message
|
@@ -276,6 +276,33 @@ module Shoulda
|
|
276
276
|
# should validate_numericality_of(:birth_day).odd
|
277
277
|
# end
|
278
278
|
#
|
279
|
+
# ##### is_in
|
280
|
+
#
|
281
|
+
# Use `is_in` to test usage of the `:in` option.
|
282
|
+
# This asserts that the attribute can take a number which is contained
|
283
|
+
# in the given range.
|
284
|
+
#
|
285
|
+
# class Person
|
286
|
+
# include ActiveModel::Model
|
287
|
+
# attr_accessor :legal_age
|
288
|
+
#
|
289
|
+
# validates_numericality_of :birth_month, in: 1..12
|
290
|
+
# end
|
291
|
+
#
|
292
|
+
# # RSpec
|
293
|
+
# RSpec.describe Person, type: :model do
|
294
|
+
# it do
|
295
|
+
# should validate_numericality_of(:birth_month).
|
296
|
+
# is_in(1..12)
|
297
|
+
# end
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# # Minitest (Shoulda)
|
301
|
+
# class PersonTest < ActiveSupport::TestCase
|
302
|
+
# should validate_numericality_of(:birth_month).
|
303
|
+
# is_in(1..12)
|
304
|
+
# end
|
305
|
+
#
|
279
306
|
# ##### with_message
|
280
307
|
#
|
281
308
|
# Use `with_message` if you are using a custom validation message.
|
@@ -330,51 +357,33 @@ module Shoulda
|
|
330
357
|
end
|
331
358
|
|
332
359
|
# @private
|
333
|
-
class ValidateNumericalityOfMatcher
|
360
|
+
class ValidateNumericalityOfMatcher < ValidationMatcher
|
334
361
|
NUMERIC_NAME = 'number'.freeze
|
335
362
|
DEFAULT_DIFF_TO_COMPARE = 1
|
336
363
|
|
337
|
-
include Qualifiers::IgnoringInterferenceByWriter
|
338
|
-
|
339
364
|
attr_reader :diff_to_compare
|
340
365
|
|
341
366
|
def initialize(attribute)
|
342
367
|
super
|
343
|
-
@attribute = attribute
|
344
368
|
@submatchers = []
|
345
369
|
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
|
346
|
-
@expects_custom_validation_message = false
|
347
370
|
@expects_to_allow_nil = false
|
348
|
-
@expects_strict = false
|
349
371
|
@allowed_type_adjective = nil
|
350
372
|
@allowed_type_name = 'number'
|
351
|
-
@context = nil
|
352
|
-
@expected_message = nil
|
353
|
-
end
|
354
|
-
|
355
|
-
def strict
|
356
|
-
@expects_strict = true
|
357
|
-
self
|
358
|
-
end
|
359
373
|
|
360
|
-
|
361
|
-
@expects_strict
|
374
|
+
add_disallow_non_numeric_value_matcher
|
362
375
|
end
|
363
376
|
|
364
377
|
def only_integer
|
365
378
|
prepare_submatcher(
|
366
|
-
NumericalityMatchers::OnlyIntegerMatcher.new(self,
|
379
|
+
NumericalityMatchers::OnlyIntegerMatcher.new(self, attribute),
|
367
380
|
)
|
368
381
|
self
|
369
382
|
end
|
370
383
|
|
371
384
|
def allow_nil
|
372
385
|
@expects_to_allow_nil = true
|
373
|
-
prepare_submatcher(
|
374
|
-
AllowValueMatcher.new(nil).
|
375
|
-
for(@attribute).
|
376
|
-
with_message(:not_a_number),
|
377
|
-
)
|
386
|
+
prepare_submatcher(allow_value_matcher(nil, :not_a_number))
|
378
387
|
self
|
379
388
|
end
|
380
389
|
|
@@ -384,60 +393,52 @@ module Shoulda
|
|
384
393
|
|
385
394
|
def odd
|
386
395
|
prepare_submatcher(
|
387
|
-
NumericalityMatchers::OddNumberMatcher.new(self,
|
396
|
+
NumericalityMatchers::OddNumberMatcher.new(self, attribute),
|
388
397
|
)
|
389
398
|
self
|
390
399
|
end
|
391
400
|
|
392
401
|
def even
|
393
402
|
prepare_submatcher(
|
394
|
-
NumericalityMatchers::EvenNumberMatcher.new(self,
|
403
|
+
NumericalityMatchers::EvenNumberMatcher.new(self, attribute),
|
395
404
|
)
|
396
405
|
self
|
397
406
|
end
|
398
407
|
|
399
408
|
def is_greater_than(value)
|
400
|
-
prepare_submatcher(comparison_matcher_for(value, :>).for(
|
409
|
+
prepare_submatcher(comparison_matcher_for(value, :>).for(attribute))
|
401
410
|
self
|
402
411
|
end
|
403
412
|
|
404
413
|
def is_greater_than_or_equal_to(value)
|
405
|
-
prepare_submatcher(comparison_matcher_for(value, :>=).for(
|
414
|
+
prepare_submatcher(comparison_matcher_for(value, :>=).for(attribute))
|
406
415
|
self
|
407
416
|
end
|
408
417
|
|
409
418
|
def is_equal_to(value)
|
410
|
-
prepare_submatcher(comparison_matcher_for(value, :==).for(
|
419
|
+
prepare_submatcher(comparison_matcher_for(value, :==).for(attribute))
|
411
420
|
self
|
412
421
|
end
|
413
422
|
|
414
423
|
def is_less_than(value)
|
415
|
-
prepare_submatcher(comparison_matcher_for(value, :<).for(
|
424
|
+
prepare_submatcher(comparison_matcher_for(value, :<).for(attribute))
|
416
425
|
self
|
417
426
|
end
|
418
427
|
|
419
428
|
def is_less_than_or_equal_to(value)
|
420
|
-
prepare_submatcher(comparison_matcher_for(value, :<=).for(
|
429
|
+
prepare_submatcher(comparison_matcher_for(value, :<=).for(attribute))
|
421
430
|
self
|
422
431
|
end
|
423
432
|
|
424
433
|
def is_other_than(value)
|
425
|
-
prepare_submatcher(comparison_matcher_for(value, :!=).for(
|
426
|
-
self
|
427
|
-
end
|
428
|
-
|
429
|
-
def with_message(message)
|
430
|
-
@expects_custom_validation_message = true
|
431
|
-
@expected_message = message
|
434
|
+
prepare_submatcher(comparison_matcher_for(value, :!=).for(attribute))
|
432
435
|
self
|
433
436
|
end
|
434
437
|
|
435
|
-
def
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
def on(context)
|
440
|
-
@context = context
|
438
|
+
def is_in(range)
|
439
|
+
prepare_submatcher(
|
440
|
+
NumericalityMatchers::RangeMatcher.new(self, attribute, range),
|
441
|
+
)
|
441
442
|
self
|
442
443
|
end
|
443
444
|
|
@@ -452,20 +453,18 @@ module Shoulda
|
|
452
453
|
end
|
453
454
|
|
454
455
|
def simple_description
|
455
|
-
|
456
|
+
String.new.tap do |description|
|
457
|
+
description << "validate that :#{attribute} looks like "
|
458
|
+
description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
|
456
459
|
|
457
|
-
|
458
|
-
|
460
|
+
if range_description.present?
|
461
|
+
description << " #{range_description}"
|
462
|
+
end
|
459
463
|
|
460
|
-
|
461
|
-
|
464
|
+
if comparison_descriptions.present?
|
465
|
+
description << " #{comparison_descriptions}"
|
466
|
+
end
|
462
467
|
end
|
463
|
-
|
464
|
-
description
|
465
|
-
end
|
466
|
-
|
467
|
-
def description
|
468
|
-
ValidationMatcher::BuildDescription.call(self, simple_description)
|
469
468
|
end
|
470
469
|
|
471
470
|
def failure_message
|
@@ -494,44 +493,29 @@ module Shoulda
|
|
494
493
|
@subject = subject
|
495
494
|
@number_of_submatchers = @submatchers.size
|
496
495
|
|
497
|
-
add_disallow_value_matcher
|
498
496
|
qualify_submatchers
|
499
497
|
end
|
500
498
|
|
501
|
-
def overall_failure_message
|
502
|
-
Shoulda::Matchers.word_wrap(
|
503
|
-
"Expected #{model.name} to #{description}, but this could not "\
|
504
|
-
'be proved.',
|
505
|
-
)
|
506
|
-
end
|
507
|
-
|
508
|
-
def overall_failure_message_when_negated
|
509
|
-
Shoulda::Matchers.word_wrap(
|
510
|
-
"Expected #{model.name} not to #{description}, but this could not "\
|
511
|
-
'be proved.',
|
512
|
-
)
|
513
|
-
end
|
514
|
-
|
515
499
|
def attribute_is_active_record_column?
|
516
|
-
columns_hash.key?(
|
500
|
+
columns_hash.key?(attribute.to_s)
|
517
501
|
end
|
518
502
|
|
519
503
|
def column_type
|
520
|
-
columns_hash[
|
504
|
+
columns_hash[attribute.to_s].type
|
521
505
|
end
|
522
506
|
|
523
507
|
def columns_hash
|
524
|
-
if
|
525
|
-
|
508
|
+
if subject.class.respond_to?(:columns_hash)
|
509
|
+
subject.class.columns_hash
|
526
510
|
else
|
527
511
|
{}
|
528
512
|
end
|
529
513
|
end
|
530
514
|
|
531
|
-
def
|
515
|
+
def add_disallow_non_numeric_value_matcher
|
532
516
|
disallow_value_matcher = DisallowValueMatcher.
|
533
517
|
new(non_numeric_value).
|
534
|
-
for(
|
518
|
+
for(attribute).
|
535
519
|
with_message(:not_a_number)
|
536
520
|
|
537
521
|
add_submatcher(disallow_value_matcher)
|
@@ -543,9 +527,9 @@ module Shoulda
|
|
543
527
|
end
|
544
528
|
|
545
529
|
def comparison_matcher_for(value, operator)
|
546
|
-
|
530
|
+
ComparisonMatcher.
|
547
531
|
new(self, value, operator).
|
548
|
-
for(
|
532
|
+
for(attribute)
|
549
533
|
end
|
550
534
|
|
551
535
|
def add_submatcher(submatcher)
|
@@ -577,8 +561,8 @@ module Shoulda
|
|
577
561
|
submatcher.with_message(@expected_message)
|
578
562
|
end
|
579
563
|
|
580
|
-
if
|
581
|
-
submatcher.on(
|
564
|
+
if context
|
565
|
+
submatcher.on(context)
|
582
566
|
end
|
583
567
|
|
584
568
|
submatcher.ignoring_interference_by_writer(
|
@@ -596,23 +580,25 @@ module Shoulda
|
|
596
580
|
end
|
597
581
|
|
598
582
|
def has_been_qualified?
|
599
|
-
@submatchers.any?
|
600
|
-
|
601
|
-
|
602
|
-
|
583
|
+
@submatchers.any? { |submatcher| submatcher_qualified?(submatcher) }
|
584
|
+
end
|
585
|
+
|
586
|
+
def submatcher_qualified?(submatcher)
|
587
|
+
Shoulda::Matchers::RailsShim.parent_of(submatcher.class) ==
|
588
|
+
NumericalityMatchers || submatcher.instance_of?(ComparisonMatcher)
|
603
589
|
end
|
604
590
|
|
605
591
|
def first_submatcher_that_fails_to_match
|
606
592
|
@_first_submatcher_that_fails_to_match ||=
|
607
593
|
@submatchers.detect do |submatcher|
|
608
|
-
!submatcher.matches?(
|
594
|
+
!submatcher.matches?(subject)
|
609
595
|
end
|
610
596
|
end
|
611
597
|
|
612
598
|
def first_submatcher_that_fails_to_not_match
|
613
599
|
@_first_submatcher_that_fails_to_not_match ||=
|
614
600
|
@submatchers.detect do |submatcher|
|
615
|
-
!submatcher.does_not_match?(
|
601
|
+
!submatcher.does_not_match?(subject)
|
616
602
|
end
|
617
603
|
end
|
618
604
|
|
@@ -673,8 +659,12 @@ module Shoulda
|
|
673
659
|
end
|
674
660
|
end
|
675
661
|
|
676
|
-
def
|
677
|
-
@
|
662
|
+
def range_description
|
663
|
+
range_submatcher = @submatchers.detect do |submatcher|
|
664
|
+
submatcher.respond_to? :range_description
|
665
|
+
end
|
666
|
+
|
667
|
+
range_submatcher&.range_description
|
678
668
|
end
|
679
669
|
|
680
670
|
def non_numeric_value
|
@@ -78,6 +78,27 @@ module Shoulda
|
|
78
78
|
# should validate_presence_of(:nickname).allow_nil
|
79
79
|
# end
|
80
80
|
#
|
81
|
+
# #### allow_blank
|
82
|
+
#
|
83
|
+
# Use `allow_blank` to assert that the attribute allows blank.
|
84
|
+
#
|
85
|
+
# class Robot
|
86
|
+
# include ActiveModel::Model
|
87
|
+
# attr_accessor :nickname
|
88
|
+
#
|
89
|
+
# validates_presence_of :nickname, allow_blank: true
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# # RSpec
|
93
|
+
# RSpec.describe Robot, type: :model do
|
94
|
+
# it { should validate_presence_of(:nickname).allow_blank }
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# # Minitest (Shoulda)
|
98
|
+
# class RobotTest < ActiveSupport::TestCase
|
99
|
+
# should validate_presence_of(:nickname).allow_blank
|
100
|
+
# end
|
101
|
+
#
|
81
102
|
# ##### on
|
82
103
|
#
|
83
104
|
# Use `on` if your validation applies only under a certain context.
|
@@ -133,6 +154,7 @@ module Shoulda
|
|
133
154
|
# @private
|
134
155
|
class ValidatePresenceOfMatcher < ValidationMatcher
|
135
156
|
include Qualifiers::AllowNil
|
157
|
+
include Qualifiers::AllowBlank
|
136
158
|
|
137
159
|
def initialize(attribute)
|
138
160
|
super
|
@@ -144,7 +166,8 @@ module Shoulda
|
|
144
166
|
|
145
167
|
possibly_ignore_interference_by_writer
|
146
168
|
|
147
|
-
if secure_password_being_validated?
|
169
|
+
if secure_password_being_validated? &&
|
170
|
+
Shoulda::Matchers::RailsShim.active_model_lt_7?
|
148
171
|
ignore_interference_by_writer.default_to(when: :blank?)
|
149
172
|
|
150
173
|
disallowed_values.all? do |value|
|
@@ -152,6 +175,7 @@ module Shoulda
|
|
152
175
|
end
|
153
176
|
else
|
154
177
|
(!expects_to_allow_nil? || allows_value_of(nil)) &&
|
178
|
+
(!expects_to_allow_blank? || allows_value_of('')) &&
|
155
179
|
disallowed_values.all? do |value|
|
156
180
|
disallows_original_or_typecast_value?(value)
|
157
181
|
end
|
@@ -171,6 +195,7 @@ module Shoulda
|
|
171
195
|
end
|
172
196
|
else
|
173
197
|
(expects_to_allow_nil? && disallows_value_of(nil)) ||
|
198
|
+
(expects_to_allow_blank? && disallows_value_of('')) ||
|
174
199
|
disallowed_values.any? do |value|
|
175
200
|
allows_original_or_typecast_value?(value)
|
176
201
|
end
|
@@ -208,7 +233,7 @@ validation for you? Instead of using `validate_presence_of`, try
|
|
208
233
|
end
|
209
234
|
|
210
235
|
def possibly_ignore_interference_by_writer
|
211
|
-
if secure_password_being_validated?
|
236
|
+
if secure_password_being_validated? && RailsShim.active_model_lt_7?
|
212
237
|
ignore_interference_by_writer.default_to(when: :blank?)
|
213
238
|
end
|
214
239
|
end
|
@@ -241,11 +266,11 @@ validation for you? Instead of using `validate_presence_of`, try
|
|
241
266
|
else
|
242
267
|
values = []
|
243
268
|
|
244
|
-
if attribute_accepts_string_values?
|
269
|
+
if attribute_accepts_string_values? && !expects_to_allow_blank?
|
245
270
|
values << ''
|
246
271
|
end
|
247
272
|
|
248
|
-
if !expects_to_allow_nil?
|
273
|
+
if !expects_to_allow_nil? && !expects_to_allow_blank?
|
249
274
|
values << nil
|
250
275
|
end
|
251
276
|
|
@@ -42,13 +42,12 @@ module Shoulda
|
|
42
42
|
description_clauses = []
|
43
43
|
|
44
44
|
if matcher.try(:expects_strict?)
|
45
|
-
description_clauses <<
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
description_clauses.last << ' on failure'
|
45
|
+
description_clauses <<
|
46
|
+
if matcher.try(:expects_custom_validation_message?)
|
47
|
+
'raising a validation exception with a custom message on failure'
|
48
|
+
else
|
49
|
+
'raising a validation exception on failure'
|
50
|
+
end
|
52
51
|
elsif matcher.try(:expects_custom_validation_message?)
|
53
52
|
description_clauses <<
|
54
53
|
'producing a custom validation error on failure'
|
@@ -186,6 +186,12 @@ module Shoulda
|
|
186
186
|
def blank_values
|
187
187
|
['', ' ', "\n", "\r", "\t", "\f"]
|
188
188
|
end
|
189
|
+
|
190
|
+
def array_column?
|
191
|
+
@subject.class.respond_to?(:columns_hash) &&
|
192
|
+
@subject.class.columns_hash[@attribute.to_s].respond_to?(:array) &&
|
193
|
+
@subject.class.columns_hash[@attribute.to_s].array
|
194
|
+
end
|
189
195
|
end
|
190
196
|
end
|
191
197
|
end
|
@@ -21,11 +21,14 @@ require 'shoulda/matchers/active_model/validate_presence_of_matcher'
|
|
21
21
|
require 'shoulda/matchers/active_model/validate_acceptance_of_matcher'
|
22
22
|
require 'shoulda/matchers/active_model/validate_confirmation_of_matcher'
|
23
23
|
require 'shoulda/matchers/active_model/validate_numericality_of_matcher'
|
24
|
+
require 'shoulda/matchers/active_model/validate_comparison_of_matcher'
|
25
|
+
require 'shoulda/matchers/active_model/comparison_matcher'
|
24
26
|
require 'shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher'
|
25
|
-
require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
|
26
27
|
require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
|
27
28
|
require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
|
28
29
|
require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
|
30
|
+
require 'shoulda/matchers/active_model/numericality_matchers/range_matcher'
|
31
|
+
require 'shoulda/matchers/active_model/numericality_matchers/submatchers'
|
29
32
|
require 'shoulda/matchers/active_model/errors'
|
30
33
|
require 'shoulda/matchers/active_model/have_secure_password_matcher'
|
31
34
|
|