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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -3
  4. data/CONTRIBUTING.md +60 -28
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +15 -12
  7. data/NEWS.md +111 -0
  8. data/README.md +94 -6
  9. data/Rakefile +10 -8
  10. data/custom_plan.rb +88 -0
  11. data/gemfiles/4.0.0.gemfile +1 -0
  12. data/gemfiles/4.0.0.gemfile.lock +21 -18
  13. data/gemfiles/4.0.1.gemfile +1 -0
  14. data/gemfiles/4.0.1.gemfile.lock +21 -18
  15. data/gemfiles/4.1.gemfile +1 -0
  16. data/gemfiles/4.1.gemfile.lock +21 -18
  17. data/gemfiles/4.2.gemfile +1 -0
  18. data/gemfiles/4.2.gemfile.lock +24 -21
  19. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -11
  20. data/lib/shoulda/matchers/active_model.rb +10 -1
  21. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +258 -180
  22. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
  23. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
  24. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +236 -0
  25. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
  26. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
  27. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
  28. data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
  29. data/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
  30. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +34 -14
  31. data/lib/shoulda/matchers/active_model/helpers.rb +9 -17
  32. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +13 -6
  33. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +13 -2
  34. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +19 -35
  35. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +13 -2
  36. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +12 -2
  37. data/lib/shoulda/matchers/active_model/qualifiers.rb +12 -0
  38. data/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
  39. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
  40. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -32
  41. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -8
  42. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -22
  43. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +27 -16
  44. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +58 -15
  45. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +22 -12
  46. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +165 -87
  47. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +7 -9
  48. data/lib/shoulda/matchers/active_model/validation_matcher.rb +111 -49
  49. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +60 -0
  50. data/lib/shoulda/matchers/active_model/validator.rb +71 -52
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +19 -5
  52. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +450 -124
  53. data/lib/shoulda/matchers/util.rb +43 -0
  54. data/lib/shoulda/matchers/util/word_wrap.rb +59 -31
  55. data/lib/shoulda/matchers/version.rb +1 -1
  56. data/script/update_gem_in_all_appraisals +1 -1
  57. data/script/update_gems_in_all_appraisals +1 -1
  58. data/spec/acceptance/multiple_libraries_integration_spec.rb +5 -2
  59. data/spec/acceptance/rails_integration_spec.rb +6 -2
  60. data/spec/spec_helper.rb +1 -3
  61. data/spec/support/acceptance/helpers/step_helpers.rb +4 -1
  62. data/spec/support/tests/current_bundle.rb +21 -7
  63. data/spec/support/unit/active_record/create_table.rb +54 -0
  64. data/spec/support/unit/attribute.rb +47 -0
  65. data/spec/support/unit/capture.rb +6 -0
  66. data/spec/support/unit/change_value.rb +111 -0
  67. data/spec/support/unit/create_model_arguments/basic.rb +135 -0
  68. data/spec/support/unit/create_model_arguments/has_many.rb +15 -0
  69. data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +74 -0
  70. data/spec/support/unit/helpers/active_record_versions.rb +1 -1
  71. data/spec/support/unit/helpers/class_builder.rb +61 -47
  72. data/spec/support/unit/helpers/database_helpers.rb +5 -3
  73. data/spec/support/unit/helpers/model_builder.rb +77 -97
  74. data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +44 -0
  75. data/spec/support/unit/load_environment.rb +12 -0
  76. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +2 -2
  77. data/spec/support/unit/matchers/fail_with_message_matcher.rb +12 -1
  78. data/spec/support/unit/model_creation_strategies/active_model.rb +111 -0
  79. data/spec/support/unit/model_creation_strategies/active_record.rb +77 -0
  80. data/spec/support/unit/model_creators.rb +19 -0
  81. data/spec/support/unit/model_creators/active_model.rb +39 -0
  82. data/spec/support/unit/model_creators/active_record.rb +43 -0
  83. data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +95 -0
  84. data/spec/support/unit/model_creators/active_record/has_many.rb +67 -0
  85. data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +42 -0
  86. data/spec/support/unit/model_creators/basic.rb +97 -0
  87. data/spec/support/unit/rails_application.rb +1 -1
  88. data/spec/support/unit/record_validating_confirmation_builder.rb +3 -7
  89. data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +79 -0
  90. data/spec/support/unit/validation_matcher_scenario.rb +62 -0
  91. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +4 -0
  92. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +575 -140
  93. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +115 -15
  94. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +42 -4
  95. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +92 -6
  96. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +122 -10
  97. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +306 -58
  98. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +122 -3
  99. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +805 -131
  100. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +196 -29
  101. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +82 -40
  102. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +600 -101
  103. data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +88 -33
  104. data/spec/unit_spec_helper.rb +10 -22
  105. data/zeus.json +11 -0
  106. metadata +64 -23
  107. data/lib/shoulda/matchers/active_model/strict_validator.rb +0 -51
  108. data/spec/support/unit/shared_examples/numerical_type_submatcher.rb +0 -15
  109. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +0 -288
  110. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +0 -100
  111. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +0 -100
  112. 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 with_short_message(message)
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 with_long_message(message)
266
+ def with_short_message(message)
264
267
  if message
265
- @long_message = message
268
+ @expects_custom_validation_message = true
269
+ @short_message = message
266
270
  end
271
+
267
272
  self
268
273
  end
269
274
 
270
- def with_message(message)
275
+ def with_long_message(message)
271
276
  if message
272
- @short_message = message
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 description
279
- description = "ensure #{@attribute} has a length "
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 << "of exactly #{@options[:minimum]}"
289
+ description << " is #{@options[:minimum]}"
283
290
  else
284
- description << "between #{@options[:minimum]} and #{@options[:maximum]}"
291
+ description << " is between #{@options[:minimum]}"
292
+ description << " and #{@options[:maximum]}"
285
293
  end
286
- else
287
- description << "of at least #{@options[:minimum]}" if @options[:minimum]
288
- description << "of at most #{@options[:maximum]}" if @options[:maximum]
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 Age
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 = 'numbers'
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
- @strict = false
318
-
319
- add_disallow_value_matcher
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
- @strict = true
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
- @submatchers.each { |matcher| matcher.with_message(message) }
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
- @submatchers.each { |matcher| matcher.on(context) }
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
- if given_numeric_column?
397
- remove_disallow_value_matcher
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 description
412
- description_parts = ["only allow #{allowed_types} for #{@attribute}"]
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
- description_parts << comparison_descriptions
430
+ description << ' ' + comparison_descriptions
416
431
  end
417
432
 
418
- if @strict
419
- description_parts.insert(1, 'strictly')
420
- description_parts.join(', ')
421
- else
422
- description_parts.join(' ')
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
- first_failing_submatcher.failure_message
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
- first_failing_submatcher.failure_message_when_negated
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
- [:integer, :float, :decimal].include?(column_type)
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[@attribute.to_s].type
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.new(NON_NUMERIC_VALUE).
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
- .new(self, value, operator)
469
- .for(@attribute)
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 update_diff_to_compare(matcher)
477
- @diff_to_compare = [@diff_to_compare, matcher.diff_to_compare].max
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
- @_first_failing_submatcher ||= @submatchers.detect do |submatcher|
570
+ @_failing_submatchers ||= @submatchers.detect do |submatcher|
482
571
  !submatcher.matches?(@subject)
483
572
  end
484
573
  end
485
574
 
486
- def allowed_types
487
- allowed_array = submatcher_allowed_types
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 submatcher_allowed_types
492
- @submatchers.inject([]){|m, s| m << s.allowed_type if s.respond_to?(:allowed_type); m }
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? ? '' : 'which are ' + submatcher_comparison_descriptions.join(' and ')
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 with_message(message)
115
- @expected_message = message if message
116
- self
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 description
131
- "require #{@attribute} to be set"
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::CouldNotSetAttributeError
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