shoulda-matchers 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +3 -3
- data/CONTRIBUTING.md +60 -28
- data/Gemfile +1 -0
- data/Gemfile.lock +15 -12
- data/NEWS.md +111 -0
- data/README.md +94 -6
- data/Rakefile +10 -8
- data/custom_plan.rb +88 -0
- data/gemfiles/4.0.0.gemfile +1 -0
- data/gemfiles/4.0.0.gemfile.lock +21 -18
- data/gemfiles/4.0.1.gemfile +1 -0
- data/gemfiles/4.0.1.gemfile.lock +21 -18
- data/gemfiles/4.1.gemfile +1 -0
- data/gemfiles/4.1.gemfile.lock +21 -18
- data/gemfiles/4.2.gemfile +1 -0
- data/gemfiles/4.2.gemfile.lock +24 -21
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -11
- data/lib/shoulda/matchers/active_model.rb +10 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +258 -180
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +236 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +34 -14
- data/lib/shoulda/matchers/active_model/helpers.rb +9 -17
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +13 -6
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +19 -35
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +13 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +12 -2
- data/lib/shoulda/matchers/active_model/qualifiers.rb +12 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -32
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -8
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -22
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +27 -16
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +58 -15
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +22 -12
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +165 -87
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +7 -9
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +111 -49
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +60 -0
- data/lib/shoulda/matchers/active_model/validator.rb +71 -52
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +19 -5
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +450 -124
- data/lib/shoulda/matchers/util.rb +43 -0
- data/lib/shoulda/matchers/util/word_wrap.rb +59 -31
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/update_gem_in_all_appraisals +1 -1
- data/script/update_gems_in_all_appraisals +1 -1
- data/spec/acceptance/multiple_libraries_integration_spec.rb +5 -2
- data/spec/acceptance/rails_integration_spec.rb +6 -2
- data/spec/spec_helper.rb +1 -3
- data/spec/support/acceptance/helpers/step_helpers.rb +4 -1
- data/spec/support/tests/current_bundle.rb +21 -7
- data/spec/support/unit/active_record/create_table.rb +54 -0
- data/spec/support/unit/attribute.rb +47 -0
- data/spec/support/unit/capture.rb +6 -0
- data/spec/support/unit/change_value.rb +111 -0
- data/spec/support/unit/create_model_arguments/basic.rb +135 -0
- data/spec/support/unit/create_model_arguments/has_many.rb +15 -0
- data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +74 -0
- data/spec/support/unit/helpers/active_record_versions.rb +1 -1
- data/spec/support/unit/helpers/class_builder.rb +61 -47
- data/spec/support/unit/helpers/database_helpers.rb +5 -3
- data/spec/support/unit/helpers/model_builder.rb +77 -97
- data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +44 -0
- data/spec/support/unit/load_environment.rb +12 -0
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +2 -2
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +12 -1
- data/spec/support/unit/model_creation_strategies/active_model.rb +111 -0
- data/spec/support/unit/model_creation_strategies/active_record.rb +77 -0
- data/spec/support/unit/model_creators.rb +19 -0
- data/spec/support/unit/model_creators/active_model.rb +39 -0
- data/spec/support/unit/model_creators/active_record.rb +43 -0
- data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +95 -0
- data/spec/support/unit/model_creators/active_record/has_many.rb +67 -0
- data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +42 -0
- data/spec/support/unit/model_creators/basic.rb +97 -0
- data/spec/support/unit/rails_application.rb +1 -1
- data/spec/support/unit/record_validating_confirmation_builder.rb +3 -7
- data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +79 -0
- data/spec/support/unit/validation_matcher_scenario.rb +62 -0
- data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +4 -0
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +575 -140
- data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +115 -15
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +42 -4
- data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +92 -6
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +122 -10
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +306 -58
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +122 -3
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +805 -131
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +196 -29
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +82 -40
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +600 -101
- data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +88 -33
- data/spec/unit_spec_helper.rb +10 -22
- data/zeus.json +11 -0
- metadata +64 -23
- data/lib/shoulda/matchers/active_model/strict_validator.rb +0 -51
- data/spec/support/unit/shared_examples/numerical_type_submatcher.rb +0 -15
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +0 -288
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +0 -100
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +0 -100
@@ -253,40 +253,50 @@ module Shoulda
|
|
253
253
|
self
|
254
254
|
end
|
255
255
|
|
256
|
-
def
|
256
|
+
def with_message(message)
|
257
257
|
if message
|
258
|
+
@expects_custom_validation_message = true
|
258
259
|
@short_message = message
|
260
|
+
@long_message = message
|
259
261
|
end
|
262
|
+
|
260
263
|
self
|
261
264
|
end
|
262
265
|
|
263
|
-
def
|
266
|
+
def with_short_message(message)
|
264
267
|
if message
|
265
|
-
@
|
268
|
+
@expects_custom_validation_message = true
|
269
|
+
@short_message = message
|
266
270
|
end
|
271
|
+
|
267
272
|
self
|
268
273
|
end
|
269
274
|
|
270
|
-
def
|
275
|
+
def with_long_message(message)
|
271
276
|
if message
|
272
|
-
@
|
277
|
+
@expects_custom_validation_message = true
|
273
278
|
@long_message = message
|
274
279
|
end
|
280
|
+
|
275
281
|
self
|
276
282
|
end
|
277
283
|
|
278
|
-
def
|
279
|
-
description =
|
284
|
+
def simple_description
|
285
|
+
description = "validate that the length of :#{@attribute}"
|
286
|
+
|
280
287
|
if @options.key?(:minimum) && @options.key?(:maximum)
|
281
288
|
if @options[:minimum] == @options[:maximum]
|
282
|
-
description << "
|
289
|
+
description << " is #{@options[:minimum]}"
|
283
290
|
else
|
284
|
-
description << "between #{@options[:minimum]}
|
291
|
+
description << " is between #{@options[:minimum]}"
|
292
|
+
description << " and #{@options[:maximum]}"
|
285
293
|
end
|
286
|
-
|
287
|
-
description << "
|
288
|
-
|
294
|
+
elsif @options.key?(:minimum)
|
295
|
+
description << " is at least #{@options[:minimum]}"
|
296
|
+
elsif @options.key?(:maximum)
|
297
|
+
description << " is at most #{@options[:maximum]}"
|
289
298
|
end
|
299
|
+
|
290
300
|
description
|
291
301
|
end
|
292
302
|
|
@@ -279,7 +279,7 @@ module Shoulda
|
|
279
279
|
#
|
280
280
|
# Use `allow_nil` to assert that the attribute allows nil.
|
281
281
|
#
|
282
|
-
# class
|
282
|
+
# class Post
|
283
283
|
# include ActiveModel::Model
|
284
284
|
# attr_accessor :age
|
285
285
|
#
|
@@ -304,27 +304,37 @@ module Shoulda
|
|
304
304
|
|
305
305
|
# @private
|
306
306
|
class ValidateNumericalityOfMatcher
|
307
|
-
NUMERIC_NAME = '
|
307
|
+
NUMERIC_NAME = 'number'
|
308
308
|
NON_NUMERIC_VALUE = 'abcd'
|
309
309
|
DEFAULT_DIFF_TO_COMPARE = 1
|
310
310
|
|
311
|
+
include Qualifiers::IgnoringInterferenceByWriter
|
312
|
+
|
311
313
|
attr_reader :diff_to_compare
|
312
314
|
|
313
315
|
def initialize(attribute)
|
316
|
+
super
|
314
317
|
@attribute = attribute
|
315
318
|
@submatchers = []
|
316
319
|
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
|
317
|
-
@
|
318
|
-
|
319
|
-
|
320
|
+
@expects_custom_validation_message = false
|
321
|
+
@expects_to_allow_nil = false
|
322
|
+
@expects_strict = false
|
323
|
+
@allowed_type_adjective = nil
|
324
|
+
@allowed_type_name = 'number'
|
325
|
+
@context = nil
|
326
|
+
@expected_message = nil
|
320
327
|
end
|
321
328
|
|
322
329
|
def strict
|
323
|
-
@
|
324
|
-
@submatchers.each(&:strict)
|
330
|
+
@expects_strict = true
|
325
331
|
self
|
326
332
|
end
|
327
333
|
|
334
|
+
def expects_strict?
|
335
|
+
@expects_strict
|
336
|
+
end
|
337
|
+
|
328
338
|
def only_integer
|
329
339
|
prepare_submatcher(
|
330
340
|
NumericalityMatchers::OnlyIntegerMatcher.new(self, @attribute)
|
@@ -333,6 +343,7 @@ module Shoulda
|
|
333
343
|
end
|
334
344
|
|
335
345
|
def allow_nil
|
346
|
+
@expects_to_allow_nil = true
|
336
347
|
prepare_submatcher(
|
337
348
|
AllowValueMatcher.new(nil)
|
338
349
|
.for(@attribute)
|
@@ -341,6 +352,10 @@ module Shoulda
|
|
341
352
|
self
|
342
353
|
end
|
343
354
|
|
355
|
+
def expects_to_allow_nil?
|
356
|
+
@expects_to_allow_nil
|
357
|
+
end
|
358
|
+
|
344
359
|
def odd
|
345
360
|
prepare_submatcher(
|
346
361
|
NumericalityMatchers::OddNumberMatcher.new(self, @attribute)
|
@@ -381,120 +396,216 @@ module Shoulda
|
|
381
396
|
end
|
382
397
|
|
383
398
|
def with_message(message)
|
384
|
-
@
|
399
|
+
@expects_custom_validation_message = true
|
400
|
+
@expected_message = message
|
385
401
|
self
|
386
402
|
end
|
387
403
|
|
404
|
+
def expects_custom_validation_message?
|
405
|
+
@expects_custom_validation_message
|
406
|
+
end
|
407
|
+
|
388
408
|
def on(context)
|
389
|
-
@
|
409
|
+
@context = context
|
390
410
|
self
|
391
411
|
end
|
392
412
|
|
393
413
|
def matches?(subject)
|
394
414
|
@subject = subject
|
415
|
+
@number_of_submatchers = @submatchers.size
|
395
416
|
|
396
|
-
|
397
|
-
|
398
|
-
end
|
399
|
-
|
400
|
-
if @submatchers.empty?
|
401
|
-
raise IneffectiveTestError.create(
|
402
|
-
model: @subject.class,
|
403
|
-
attribute: @attribute,
|
404
|
-
column_type: column_type
|
405
|
-
)
|
406
|
-
end
|
417
|
+
add_disallow_value_matcher
|
418
|
+
qualify_submatchers
|
407
419
|
|
408
420
|
first_failing_submatcher.nil?
|
409
421
|
end
|
410
422
|
|
411
|
-
def
|
412
|
-
|
423
|
+
def simple_description
|
424
|
+
description = ''
|
425
|
+
|
426
|
+
description << "validate that :#{@attribute} looks like "
|
427
|
+
description << Shoulda::Matchers::Util.a_or_an(full_allowed_type)
|
413
428
|
|
414
429
|
if comparison_descriptions.present?
|
415
|
-
|
430
|
+
description << ' ' + comparison_descriptions
|
416
431
|
end
|
417
432
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
end
|
433
|
+
description
|
434
|
+
end
|
435
|
+
|
436
|
+
def description
|
437
|
+
ValidationMatcher::BuildDescription.call(self, simple_description)
|
424
438
|
end
|
425
439
|
|
426
440
|
def failure_message
|
427
|
-
|
441
|
+
overall_failure_message.dup.tap do |message|
|
442
|
+
message << "\n"
|
443
|
+
message << failure_message_for_first_failing_submatcher
|
444
|
+
end
|
428
445
|
end
|
429
446
|
|
430
447
|
def failure_message_when_negated
|
431
|
-
|
448
|
+
overall_failure_message_when_negated.dup.tap do |message|
|
449
|
+
if submatcher_failure_message_when_negated.present?
|
450
|
+
raise "hmm, this needs to be implemented."
|
451
|
+
message << "\n"
|
452
|
+
message << Shoulda::Matchers.word_wrap(
|
453
|
+
submatcher_failure_message_when_negated,
|
454
|
+
indent: 2
|
455
|
+
)
|
456
|
+
end
|
457
|
+
end
|
432
458
|
end
|
433
459
|
|
434
460
|
def given_numeric_column?
|
435
|
-
|
461
|
+
attribute_is_active_record_column? &&
|
462
|
+
[:integer, :float, :decimal].include?(column_type)
|
436
463
|
end
|
437
464
|
|
438
465
|
private
|
439
466
|
|
467
|
+
def model
|
468
|
+
@subject.class
|
469
|
+
end
|
470
|
+
|
471
|
+
def overall_failure_message
|
472
|
+
Shoulda::Matchers.word_wrap(
|
473
|
+
"#{model.name} did not properly #{description}."
|
474
|
+
)
|
475
|
+
end
|
476
|
+
|
477
|
+
def overall_failure_message_when_negated
|
478
|
+
Shoulda::Matchers.word_wrap(
|
479
|
+
"Expected #{model.name} not to #{description}, but it did."
|
480
|
+
)
|
481
|
+
end
|
482
|
+
|
483
|
+
def attribute_is_active_record_column?
|
484
|
+
columns_hash.key?(@attribute.to_s)
|
485
|
+
end
|
486
|
+
|
440
487
|
def column_type
|
488
|
+
columns_hash[@attribute.to_s].type
|
489
|
+
end
|
490
|
+
|
491
|
+
def columns_hash
|
441
492
|
if @subject.class.respond_to?(:columns_hash)
|
442
|
-
@subject.class.columns_hash
|
493
|
+
@subject.class.columns_hash
|
494
|
+
else
|
495
|
+
{}
|
443
496
|
end
|
444
497
|
end
|
445
498
|
|
446
499
|
def add_disallow_value_matcher
|
447
|
-
disallow_value_matcher = DisallowValueMatcher.
|
500
|
+
disallow_value_matcher = DisallowValueMatcher.
|
501
|
+
new(NON_NUMERIC_VALUE).
|
448
502
|
for(@attribute).
|
449
503
|
with_message(:not_a_number)
|
450
504
|
|
451
505
|
add_submatcher(disallow_value_matcher)
|
452
506
|
end
|
453
507
|
|
454
|
-
def remove_disallow_value_matcher
|
455
|
-
@submatchers.shift
|
456
|
-
end
|
457
|
-
|
458
508
|
def prepare_submatcher(submatcher)
|
459
509
|
add_submatcher(submatcher)
|
460
|
-
|
461
|
-
if submatcher.respond_to?(:diff_to_compare)
|
462
|
-
update_diff_to_compare(submatcher)
|
463
|
-
end
|
510
|
+
submatcher
|
464
511
|
end
|
465
512
|
|
466
513
|
def comparison_matcher_for(value, operator)
|
467
|
-
NumericalityMatchers::ComparisonMatcher
|
468
|
-
|
469
|
-
|
514
|
+
NumericalityMatchers::ComparisonMatcher.
|
515
|
+
new(self, value, operator).
|
516
|
+
for(@attribute)
|
470
517
|
end
|
471
518
|
|
472
519
|
def add_submatcher(submatcher)
|
520
|
+
if submatcher.respond_to?(:allowed_type_name)
|
521
|
+
@allowed_type_name = submatcher.allowed_type_name
|
522
|
+
end
|
523
|
+
|
524
|
+
if submatcher.respond_to?(:allowed_type_adjective)
|
525
|
+
@allowed_type_adjective = submatcher.allowed_type_adjective
|
526
|
+
end
|
527
|
+
|
528
|
+
if submatcher.respond_to?(:diff_to_compare)
|
529
|
+
@diff_to_compare = [@diff_to_compare, submatcher.diff_to_compare].max
|
530
|
+
end
|
531
|
+
|
473
532
|
@submatchers << submatcher
|
474
533
|
end
|
475
534
|
|
476
|
-
def
|
477
|
-
@
|
535
|
+
def qualify_submatchers
|
536
|
+
@submatchers.each do |submatcher|
|
537
|
+
if @expects_strict
|
538
|
+
submatcher.strict(@expects_strict)
|
539
|
+
end
|
540
|
+
|
541
|
+
if @expected_message.present?
|
542
|
+
submatcher.with_message(@expected_message)
|
543
|
+
end
|
544
|
+
|
545
|
+
if @context
|
546
|
+
submatcher.on(@context)
|
547
|
+
end
|
548
|
+
|
549
|
+
submatcher.ignoring_interference_by_writer(
|
550
|
+
ignore_interference_by_writer
|
551
|
+
)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def number_of_submatchers_for_failure_message
|
556
|
+
if has_been_qualified?
|
557
|
+
@submatchers.size - 1
|
558
|
+
else
|
559
|
+
@submatchers.size
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def has_been_qualified?
|
564
|
+
@submatchers.any? do |submatcher|
|
565
|
+
submatcher.class.parent == NumericalityMatchers
|
566
|
+
end
|
478
567
|
end
|
479
568
|
|
480
569
|
def first_failing_submatcher
|
481
|
-
@
|
570
|
+
@_failing_submatchers ||= @submatchers.detect do |submatcher|
|
482
571
|
!submatcher.matches?(@subject)
|
483
572
|
end
|
484
573
|
end
|
485
574
|
|
486
|
-
def
|
487
|
-
|
488
|
-
allowed_array.empty? ? NUMERIC_NAME : allowed_array.join(', ')
|
575
|
+
def submatcher_failure_message
|
576
|
+
first_failing_submatcher.failure_message
|
489
577
|
end
|
490
578
|
|
491
|
-
def
|
492
|
-
|
579
|
+
def submatcher_failure_message_when_negated
|
580
|
+
first_failing_submatcher.failure_message_when_negated
|
581
|
+
end
|
582
|
+
|
583
|
+
def failure_message_for_first_failing_submatcher
|
584
|
+
submatcher = first_failing_submatcher
|
585
|
+
|
586
|
+
if number_of_submatchers_for_failure_message > 1
|
587
|
+
submatcher_description = submatcher.simple_description.
|
588
|
+
sub(/\bvalidate that\b/, 'validates').
|
589
|
+
sub(/\bdisallow\b/, 'disallows').
|
590
|
+
sub(/\ballow\b/, 'allows')
|
591
|
+
submatcher_message =
|
592
|
+
"In checking that #{model.name} #{submatcher_description}, " +
|
593
|
+
submatcher.failure_message[0].downcase +
|
594
|
+
submatcher.failure_message[1..-1]
|
595
|
+
else
|
596
|
+
submatcher_message = submatcher.failure_message
|
597
|
+
end
|
598
|
+
|
599
|
+
Shoulda::Matchers.word_wrap(submatcher_message, indent: 2)
|
600
|
+
end
|
601
|
+
|
602
|
+
def full_allowed_type
|
603
|
+
"#{@allowed_type_adjective} #{@allowed_type_name}".strip
|
493
604
|
end
|
494
605
|
|
495
606
|
def comparison_descriptions
|
496
607
|
description_array = submatcher_comparison_descriptions
|
497
|
-
description_array.empty? ? '' :
|
608
|
+
description_array.empty? ? '' : submatcher_comparison_descriptions.join(' and ')
|
498
609
|
end
|
499
610
|
|
500
611
|
def submatcher_comparison_descriptions
|
@@ -505,39 +616,6 @@ module Shoulda
|
|
505
616
|
arr
|
506
617
|
end
|
507
618
|
end
|
508
|
-
|
509
|
-
class IneffectiveTestError < Shoulda::Matchers::Error
|
510
|
-
attr_accessor :model, :attribute, :column_type
|
511
|
-
|
512
|
-
def message
|
513
|
-
Shoulda::Matchers.word_wrap <<-MESSAGE
|
514
|
-
You are attempting to use validate_numericality_of, but the attribute you're
|
515
|
-
testing, :#{attribute}, is #{a_or_an(column_type)} column. One of the things
|
516
|
-
that the numericality matcher does is to assert that setting :#{attribute} to a
|
517
|
-
string that doesn't look like #{a_or_an(column_type)} will cause your
|
518
|
-
#{humanized_model_name} to become invalid. In this case, it's impossible to make
|
519
|
-
this assertion since :#{attribute} will typecast any incoming value to
|
520
|
-
#{a_or_an(column_type)}. This means that it's already guaranteed to be numeric!
|
521
|
-
Since this matcher isn't doing anything, you can remove it from your model
|
522
|
-
tests, and in fact, you can remove the validation from your model as it isn't
|
523
|
-
doing anything either.
|
524
|
-
MESSAGE
|
525
|
-
end
|
526
|
-
|
527
|
-
private
|
528
|
-
|
529
|
-
def humanized_model_name
|
530
|
-
model.name.humanize.downcase
|
531
|
-
end
|
532
|
-
|
533
|
-
def a_or_an(next_word)
|
534
|
-
if next_word =~ /[aeiou]/
|
535
|
-
"an #{next_word}"
|
536
|
-
else
|
537
|
-
"a #{next_word}"
|
538
|
-
end
|
539
|
-
end
|
540
|
-
end
|
541
619
|
end
|
542
620
|
end
|
543
621
|
end
|
@@ -111,24 +111,24 @@ module Shoulda
|
|
111
111
|
|
112
112
|
# @private
|
113
113
|
class ValidatePresenceOfMatcher < ValidationMatcher
|
114
|
-
def
|
115
|
-
|
116
|
-
|
114
|
+
def initialize(attribute)
|
115
|
+
super
|
116
|
+
@expected_message = :blank
|
117
117
|
end
|
118
118
|
|
119
119
|
def matches?(subject)
|
120
120
|
super(subject)
|
121
|
-
@expected_message ||= :blank
|
122
121
|
|
123
122
|
if secure_password_being_validated?
|
123
|
+
ignore_interference_by_writer.default_to(when: :blank?)
|
124
124
|
disallows_and_double_checks_value_of!(blank_value, @expected_message)
|
125
125
|
else
|
126
126
|
disallows_original_or_typecast_value?(blank_value, @expected_message)
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
def
|
131
|
-
"
|
130
|
+
def simple_description
|
131
|
+
"validate that :#{@attribute} cannot be empty/falsy"
|
132
132
|
end
|
133
133
|
|
134
134
|
private
|
@@ -141,14 +141,12 @@ module Shoulda
|
|
141
141
|
|
142
142
|
def disallows_and_double_checks_value_of!(value, message)
|
143
143
|
disallows_value_of(value, message)
|
144
|
-
rescue ActiveModel::AllowValueMatcher::
|
144
|
+
rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
|
145
145
|
raise ActiveModel::CouldNotSetPasswordError.create(@subject.class)
|
146
146
|
end
|
147
147
|
|
148
148
|
def disallows_original_or_typecast_value?(value, message)
|
149
149
|
disallows_value_of(blank_value, @expected_message)
|
150
|
-
rescue ActiveModel::AllowValueMatcher::CouldNotSetAttributeError => error
|
151
|
-
error.actual_value.blank?
|
152
150
|
end
|
153
151
|
|
154
152
|
def blank_value
|