shoulda-matchers 6.0.0 → 6.2.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/README.md +18 -9
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -8
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +13 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +37 -1
- data/lib/shoulda/matchers/active_model/comparison_matcher.rb +1 -6
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +7 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +0 -5
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +0 -6
- data/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +11 -13
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +20 -8
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +9 -11
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +6 -7
- data/lib/shoulda/matchers/active_record/association_matcher.rb +543 -15
- 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/encrypt_matcher.rb +174 -0
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +10 -10
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/normalize_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/uniqueness/model.rb +1 -1
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +82 -70
- data/lib/shoulda/matchers/active_record.rb +1 -0
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -6
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -6
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +12 -14
- 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/util.rb +17 -19
- data/lib/shoulda/matchers/version.rb +1 -1
- metadata +4 -3
| @@ -144,6 +144,28 @@ module Shoulda | |
| 144 144 | 
             
                  #         with_foreign_key('country_id')
         | 
| 145 145 | 
             
                  #     end
         | 
| 146 146 | 
             
                  #
         | 
| 147 | 
            +
                  # ##### with_foreign_type
         | 
| 148 | 
            +
                  #
         | 
| 149 | 
            +
                  # Use `with_foreign_type` to test usage of the `:foreign_type` option.
         | 
| 150 | 
            +
                  #
         | 
| 151 | 
            +
                  #     class Visitor < ActiveRecord::Base
         | 
| 152 | 
            +
                  #       belongs_to :location, foreign_type: 'facility_type', polymorphic: true
         | 
| 153 | 
            +
                  #     end
         | 
| 154 | 
            +
                  #
         | 
| 155 | 
            +
                  #     # RSpec
         | 
| 156 | 
            +
                  #     RSpec.describe Visitor, type: :model do
         | 
| 157 | 
            +
                  #       it do
         | 
| 158 | 
            +
                  #         should belong_to(:location).
         | 
| 159 | 
            +
                  #           with_foreign_type('facility_type')
         | 
| 160 | 
            +
                  #       end
         | 
| 161 | 
            +
                  #     end
         | 
| 162 | 
            +
                  #
         | 
| 163 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 164 | 
            +
                  #     class VisitorTest < ActiveSupport::TestCase
         | 
| 165 | 
            +
                  #       should belong_to(:location).
         | 
| 166 | 
            +
                  #         with_foreign_type('facility_type')
         | 
| 167 | 
            +
                  #     end
         | 
| 168 | 
            +
                  #
         | 
| 147 169 | 
             
                  # ##### dependent
         | 
| 148 170 | 
             
                  #
         | 
| 149 171 | 
             
                  # Use `dependent` to assert that the `:dependent` option was specified.
         | 
| @@ -217,6 +239,36 @@ module Shoulda | |
| 217 239 | 
             
                  #       should belong_to(:organization).touch(true)
         | 
| 218 240 | 
             
                  #     end
         | 
| 219 241 | 
             
                  #
         | 
| 242 | 
            +
                  # ##### strict_loading
         | 
| 243 | 
            +
                  #
         | 
| 244 | 
            +
                  # Use `strict_loading` to assert that the `:strict_loading` option was specified.
         | 
| 245 | 
            +
                  #
         | 
| 246 | 
            +
                  #     class Organization < ActiveRecord::Base
         | 
| 247 | 
            +
                  #       has_many :people, strict_loading: true
         | 
| 248 | 
            +
                  #     end
         | 
| 249 | 
            +
                  #
         | 
| 250 | 
            +
                  #     # RSpec
         | 
| 251 | 
            +
                  #     RSpec.describe Organization, type: :model do
         | 
| 252 | 
            +
                  #       it { should have_many(:people).strict_loading(true) }
         | 
| 253 | 
            +
                  #     end
         | 
| 254 | 
            +
                  #
         | 
| 255 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 256 | 
            +
                  #     class OrganizationTest < ActiveSupport::TestCase
         | 
| 257 | 
            +
                  #       should have_many(:people).strict_loading(true)
         | 
| 258 | 
            +
                  #     end
         | 
| 259 | 
            +
                  #
         | 
| 260 | 
            +
                  # Default value is true when no argument is specified
         | 
| 261 | 
            +
                  #
         | 
| 262 | 
            +
                  #     # RSpec
         | 
| 263 | 
            +
                  #     RSpec.describe Organization, type: :model do
         | 
| 264 | 
            +
                  #       it { should have_many(:people).strict_loading }
         | 
| 265 | 
            +
                  #     end
         | 
| 266 | 
            +
                  #
         | 
| 267 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 268 | 
            +
                  #     class OrganizationTest < ActiveSupport::TestCase
         | 
| 269 | 
            +
                  #       should have_many(:people).strict_loading
         | 
| 270 | 
            +
                  #     end
         | 
| 271 | 
            +
                  #
         | 
| 220 272 | 
             
                  # ##### autosave
         | 
| 221 273 | 
             
                  #
         | 
| 222 274 | 
             
                  # Use `autosave` to assert that the `:autosave` option was specified.
         | 
| @@ -326,6 +378,316 @@ module Shoulda | |
| 326 378 | 
             
                    AssociationMatcher.new(:belongs_to, name)
         | 
| 327 379 | 
             
                  end
         | 
| 328 380 |  | 
| 381 | 
            +
                  # The `have_delegated_type` matcher is used to ensure that a `belong_to` association
         | 
| 382 | 
            +
                  # exists on your model using the delegated_type macro.
         | 
| 383 | 
            +
                  #
         | 
| 384 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 385 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck)
         | 
| 386 | 
            +
                  #     end
         | 
| 387 | 
            +
                  #
         | 
| 388 | 
            +
                  #     # RSpec
         | 
| 389 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 390 | 
            +
                  #       it { should have_delegated_type(:drivable) }
         | 
| 391 | 
            +
                  #     end
         | 
| 392 | 
            +
                  #
         | 
| 393 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 394 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 395 | 
            +
                  #       should have_delegated_type(:drivable)
         | 
| 396 | 
            +
                  #     end
         | 
| 397 | 
            +
                  #
         | 
| 398 | 
            +
                  # #### Qualifiers
         | 
| 399 | 
            +
                  #
         | 
| 400 | 
            +
                  # ##### types
         | 
| 401 | 
            +
                  #
         | 
| 402 | 
            +
                  # Use `types` to test the types that are allowed for the association.
         | 
| 403 | 
            +
                  #
         | 
| 404 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 405 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck)
         | 
| 406 | 
            +
                  #     end
         | 
| 407 | 
            +
                  #
         | 
| 408 | 
            +
                  #     # RSpec
         | 
| 409 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 410 | 
            +
                  #       it do
         | 
| 411 | 
            +
                  #         should have_delegated_type(:drivable).
         | 
| 412 | 
            +
                  #           types(%w(Car Truck))
         | 
| 413 | 
            +
                  #       end
         | 
| 414 | 
            +
                  #     end
         | 
| 415 | 
            +
                  #
         | 
| 416 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 417 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 418 | 
            +
                  #       should have_delegated_type(:drivable).
         | 
| 419 | 
            +
                  #         types(%w(Car Truck))
         | 
| 420 | 
            +
                  #     end
         | 
| 421 | 
            +
                  #
         | 
| 422 | 
            +
                  # ##### conditions
         | 
| 423 | 
            +
                  #
         | 
| 424 | 
            +
                  # Use `conditions` if your association is defined with a scope that sets
         | 
| 425 | 
            +
                  # the `where` clause.
         | 
| 426 | 
            +
                  #
         | 
| 427 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 428 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), scope: -> { where(with_wheels: true) }
         | 
| 429 | 
            +
                  #     end
         | 
| 430 | 
            +
                  #
         | 
| 431 | 
            +
                  #     # RSpec
         | 
| 432 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 433 | 
            +
                  #       it do
         | 
| 434 | 
            +
                  #         should have_delegated_type(:drivable).
         | 
| 435 | 
            +
                  #           conditions(with_wheels: true)
         | 
| 436 | 
            +
                  #       end
         | 
| 437 | 
            +
                  #     end
         | 
| 438 | 
            +
                  #
         | 
| 439 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 440 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 441 | 
            +
                  #       should have_delegated_type(:drivable).
         | 
| 442 | 
            +
                  #         conditions(everyone_is_perfect: false)
         | 
| 443 | 
            +
                  #     end
         | 
| 444 | 
            +
                  #
         | 
| 445 | 
            +
                  # ##### order
         | 
| 446 | 
            +
                  #
         | 
| 447 | 
            +
                  # Use `order` if your association is defined with a scope that sets the
         | 
| 448 | 
            +
                  # `order` clause.
         | 
| 449 | 
            +
                  #
         | 
| 450 | 
            +
                  #     class Person < ActiveRecord::Base
         | 
| 451 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), scope: -> { order('wheels desc') }
         | 
| 452 | 
            +
                  #     end
         | 
| 453 | 
            +
                  #
         | 
| 454 | 
            +
                  #     # RSpec
         | 
| 455 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 456 | 
            +
                  #       it { should have_delegated_type(:drivable).order('wheels desc') }
         | 
| 457 | 
            +
                  #     end
         | 
| 458 | 
            +
                  #
         | 
| 459 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 460 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 461 | 
            +
                  #       should have_delegated_type(:drivable).order('wheels desc')
         | 
| 462 | 
            +
                  #     end
         | 
| 463 | 
            +
                  #
         | 
| 464 | 
            +
                  # ##### with_primary_key
         | 
| 465 | 
            +
                  #
         | 
| 466 | 
            +
                  # Use `with_primary_key` to test usage of the `:primary_key` option.
         | 
| 467 | 
            +
                  #
         | 
| 468 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 469 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), primary_key: 'vehicle_id'
         | 
| 470 | 
            +
                  #     end
         | 
| 471 | 
            +
                  #
         | 
| 472 | 
            +
                  #     # RSpec
         | 
| 473 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 474 | 
            +
                  #       it do
         | 
| 475 | 
            +
                  #         should have_delegated_type(:drivable).
         | 
| 476 | 
            +
                  #           with_primary_key('vehicle_id')
         | 
| 477 | 
            +
                  #       end
         | 
| 478 | 
            +
                  #     end
         | 
| 479 | 
            +
                  #
         | 
| 480 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 481 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 482 | 
            +
                  #       should have_delegated_type(:drivable).
         | 
| 483 | 
            +
                  #         with_primary_key('vehicle_id')
         | 
| 484 | 
            +
                  #     end
         | 
| 485 | 
            +
                  #
         | 
| 486 | 
            +
                  # ##### with_foreign_key
         | 
| 487 | 
            +
                  #
         | 
| 488 | 
            +
                  # Use `with_foreign_key` to test usage of the `:foreign_key` option.
         | 
| 489 | 
            +
                  #
         | 
| 490 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 491 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), foreign_key: 'drivable_uuid'
         | 
| 492 | 
            +
                  #     end
         | 
| 493 | 
            +
                  #
         | 
| 494 | 
            +
                  #     # RSpec
         | 
| 495 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 496 | 
            +
                  #       it do
         | 
| 497 | 
            +
                  #         should have_delegated_type(:drivable).
         | 
| 498 | 
            +
                  #           with_foreign_key('drivable_uuid')
         | 
| 499 | 
            +
                  #       end
         | 
| 500 | 
            +
                  #     end
         | 
| 501 | 
            +
                  #
         | 
| 502 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 503 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 504 | 
            +
                  #       should have_delegated_type(:drivable).
         | 
| 505 | 
            +
                  #         with_foreign_key('drivable_uuid')
         | 
| 506 | 
            +
                  #     end
         | 
| 507 | 
            +
                  #
         | 
| 508 | 
            +
                  # ##### dependent
         | 
| 509 | 
            +
                  #
         | 
| 510 | 
            +
                  # Use `dependent` to assert that the `:dependent` option was specified.
         | 
| 511 | 
            +
                  #
         | 
| 512 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 513 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), dependent: :destroy
         | 
| 514 | 
            +
                  #     end
         | 
| 515 | 
            +
                  #
         | 
| 516 | 
            +
                  #     # RSpec
         | 
| 517 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 518 | 
            +
                  #       it { should have_delegated_type(:drivable).dependent(:destroy) }
         | 
| 519 | 
            +
                  #     end
         | 
| 520 | 
            +
                  #
         | 
| 521 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 522 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 523 | 
            +
                  #       should have_delegated_type(:drivable).dependent(:destroy)
         | 
| 524 | 
            +
                  #     end
         | 
| 525 | 
            +
                  #
         | 
| 526 | 
            +
                  # To assert that *any* `:dependent` option was specified, use `true`:
         | 
| 527 | 
            +
                  #
         | 
| 528 | 
            +
                  #     # RSpec
         | 
| 529 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 530 | 
            +
                  #       it { should have_delegated_type(:drivable).dependent(true) }
         | 
| 531 | 
            +
                  #     end
         | 
| 532 | 
            +
                  #
         | 
| 533 | 
            +
                  # To assert that *no* `:dependent` option was specified, use `false`:
         | 
| 534 | 
            +
                  #
         | 
| 535 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 536 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck)
         | 
| 537 | 
            +
                  #     end
         | 
| 538 | 
            +
                  #
         | 
| 539 | 
            +
                  #     # RSpec
         | 
| 540 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 541 | 
            +
                  #       it { should have_delegated_type(:drivable).dependent(false) }
         | 
| 542 | 
            +
                  #     end
         | 
| 543 | 
            +
                  #
         | 
| 544 | 
            +
                  # ##### counter_cache
         | 
| 545 | 
            +
                  #
         | 
| 546 | 
            +
                  # Use `counter_cache` to assert that the `:counter_cache` option was
         | 
| 547 | 
            +
                  # specified.
         | 
| 548 | 
            +
                  #
         | 
| 549 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 550 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), counter_cache: true
         | 
| 551 | 
            +
                  #     end
         | 
| 552 | 
            +
                  #
         | 
| 553 | 
            +
                  #     # RSpec
         | 
| 554 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 555 | 
            +
                  #       it { should have_delegated_type(:drivable).counter_cache(true) }
         | 
| 556 | 
            +
                  #     end
         | 
| 557 | 
            +
                  #
         | 
| 558 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 559 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 560 | 
            +
                  #       should have_delegated_type(:drivable).counter_cache(true)
         | 
| 561 | 
            +
                  #     end
         | 
| 562 | 
            +
                  #
         | 
| 563 | 
            +
                  # ##### touch
         | 
| 564 | 
            +
                  #
         | 
| 565 | 
            +
                  # Use `touch` to assert that the `:touch` option was specified.
         | 
| 566 | 
            +
                  #
         | 
| 567 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 568 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), touch: true
         | 
| 569 | 
            +
                  #     end
         | 
| 570 | 
            +
                  #
         | 
| 571 | 
            +
                  #     # RSpec
         | 
| 572 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 573 | 
            +
                  #       it { should have_delegated_type(:drivable).touch(true) }
         | 
| 574 | 
            +
                  #     end
         | 
| 575 | 
            +
                  #
         | 
| 576 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 577 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 578 | 
            +
                  #       should have_delegated_type(:drivable).touch(true)
         | 
| 579 | 
            +
                  #     end
         | 
| 580 | 
            +
                  #
         | 
| 581 | 
            +
                  # ##### autosave
         | 
| 582 | 
            +
                  #
         | 
| 583 | 
            +
                  # Use `autosave` to assert that the `:autosave` option was specified.
         | 
| 584 | 
            +
                  #
         | 
| 585 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 586 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), autosave: true
         | 
| 587 | 
            +
                  #     end
         | 
| 588 | 
            +
                  #
         | 
| 589 | 
            +
                  #     # RSpec
         | 
| 590 | 
            +
                  #     RSpec.describe Vehicle, type: :model do
         | 
| 591 | 
            +
                  #       it { should have_delegated_type(:drivable).autosave(true) }
         | 
| 592 | 
            +
                  #     end
         | 
| 593 | 
            +
                  #
         | 
| 594 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 595 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 596 | 
            +
                  #       should have_delegated_type(:drivable).autosave(true)
         | 
| 597 | 
            +
                  #     end
         | 
| 598 | 
            +
                  #
         | 
| 599 | 
            +
                  # ##### inverse_of
         | 
| 600 | 
            +
                  #
         | 
| 601 | 
            +
                  # Use `inverse_of` to assert that the `:inverse_of` option was specified.
         | 
| 602 | 
            +
                  #
         | 
| 603 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 604 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), inverse_of: :vehicle
         | 
| 605 | 
            +
                  #     end
         | 
| 606 | 
            +
                  #
         | 
| 607 | 
            +
                  #     # RSpec
         | 
| 608 | 
            +
                  #     describe Vehicle
         | 
| 609 | 
            +
                  #       it { should have_delegated_type(:drivable).inverse_of(:vehicle) }
         | 
| 610 | 
            +
                  #     end
         | 
| 611 | 
            +
                  #
         | 
| 612 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 613 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 614 | 
            +
                  #       should have_delegated_type(:drivable).inverse_of(:vehicle)
         | 
| 615 | 
            +
                  #     end
         | 
| 616 | 
            +
                  #
         | 
| 617 | 
            +
                  # ##### required
         | 
| 618 | 
            +
                  #
         | 
| 619 | 
            +
                  # Use `required` to assert that the association is not allowed to be nil.
         | 
| 620 | 
            +
                  # (Enabled by default in Rails 5+.)
         | 
| 621 | 
            +
                  #
         | 
| 622 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 623 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), required: true
         | 
| 624 | 
            +
                  #     end
         | 
| 625 | 
            +
                  #
         | 
| 626 | 
            +
                  #     # RSpec
         | 
| 627 | 
            +
                  #     describe Vehicle
         | 
| 628 | 
            +
                  #       it { should have_delegated_type(:drivable).required }
         | 
| 629 | 
            +
                  #     end
         | 
| 630 | 
            +
                  #
         | 
| 631 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 632 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 633 | 
            +
                  #       should have_delegated_type(:drivable).required
         | 
| 634 | 
            +
                  #     end
         | 
| 635 | 
            +
                  #
         | 
| 636 | 
            +
                  # ##### without_validating_presence
         | 
| 637 | 
            +
                  #
         | 
| 638 | 
            +
                  # Use `without_validating_presence` with `belong_to` to prevent the
         | 
| 639 | 
            +
                  # matcher from checking whether the association disallows nil (Rails 5+
         | 
| 640 | 
            +
                  # only). This can be helpful if you have a custom hook that always sets
         | 
| 641 | 
            +
                  # the association to a meaningful value:
         | 
| 642 | 
            +
                  #
         | 
| 643 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 644 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck)
         | 
| 645 | 
            +
                  #
         | 
| 646 | 
            +
                  #       before_validation :autoassign_drivable
         | 
| 647 | 
            +
                  #
         | 
| 648 | 
            +
                  #       private
         | 
| 649 | 
            +
                  #
         | 
| 650 | 
            +
                  #       def autoassign_drivable
         | 
| 651 | 
            +
                  #         self.drivable = Car.create!
         | 
| 652 | 
            +
                  #       end
         | 
| 653 | 
            +
                  #     end
         | 
| 654 | 
            +
                  #
         | 
| 655 | 
            +
                  #     # RSpec
         | 
| 656 | 
            +
                  #     describe Vehicle
         | 
| 657 | 
            +
                  #       it { should have_delegated_type(:drivable).without_validating_presence }
         | 
| 658 | 
            +
                  #     end
         | 
| 659 | 
            +
                  #
         | 
| 660 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 661 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 662 | 
            +
                  #       should have_delegated_type(:drivable).without_validating_presence
         | 
| 663 | 
            +
                  #     end
         | 
| 664 | 
            +
                  #
         | 
| 665 | 
            +
                  # ##### optional
         | 
| 666 | 
            +
                  #
         | 
| 667 | 
            +
                  # Use `optional` to assert that the association is allowed to be nil.
         | 
| 668 | 
            +
                  # (Rails 5+ only.)
         | 
| 669 | 
            +
                  #
         | 
| 670 | 
            +
                  #     class Vehicle < ActiveRecord::Base
         | 
| 671 | 
            +
                  #       delegated_type :drivable, types: %w(Car Truck), optional: true
         | 
| 672 | 
            +
                  #     end
         | 
| 673 | 
            +
                  #
         | 
| 674 | 
            +
                  #     # RSpec
         | 
| 675 | 
            +
                  #     describe Vehicle
         | 
| 676 | 
            +
                  #       it { should have_delegated_type(:drivable).optional }
         | 
| 677 | 
            +
                  #     end
         | 
| 678 | 
            +
                  #
         | 
| 679 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 680 | 
            +
                  #     class VehicleTest < ActiveSupport::TestCase
         | 
| 681 | 
            +
                  #       should have_delegated_type(:drivable).optional
         | 
| 682 | 
            +
                  #     end
         | 
| 683 | 
            +
                  #
         | 
| 684 | 
            +
                  # @return [AssociationMatcher]
         | 
| 685 | 
            +
                  #
         | 
| 686 | 
            +
             | 
| 687 | 
            +
                  def have_delegated_type(name)
         | 
| 688 | 
            +
                    AssociationMatcher.new(:belongs_to, name)
         | 
| 689 | 
            +
                  end
         | 
| 690 | 
            +
             | 
| 329 691 | 
             
                  # The `have_many` matcher is used to test that a `has_many` or `has_many
         | 
| 330 692 | 
             
                  # :through` association exists on your model.
         | 
| 331 693 | 
             
                  #
         | 
| @@ -455,6 +817,24 @@ module Shoulda | |
| 455 817 | 
             
                  #       should have_many(:worries).with_foreign_key('worrier_id')
         | 
| 456 818 | 
             
                  #     end
         | 
| 457 819 | 
             
                  #
         | 
| 820 | 
            +
                  # ##### with_foreign_type
         | 
| 821 | 
            +
                  #
         | 
| 822 | 
            +
                  # Use `with_foreign_type` to test usage of the `:foreign_type` option.
         | 
| 823 | 
            +
                  #
         | 
| 824 | 
            +
                  #     class Hotel < ActiveRecord::Base
         | 
| 825 | 
            +
                  #       has_many :visitors, foreign_key: 'facility_type', as: :location
         | 
| 826 | 
            +
                  #     end
         | 
| 827 | 
            +
                  #
         | 
| 828 | 
            +
                  #     # RSpec
         | 
| 829 | 
            +
                  #     RSpec.describe Hotel, type: :model do
         | 
| 830 | 
            +
                  #       it { should have_many(:visitors).with_foreign_type('facility_type') }
         | 
| 831 | 
            +
                  #     end
         | 
| 832 | 
            +
                  #
         | 
| 833 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 834 | 
            +
                  #     class HotelTest < ActiveSupport::TestCase
         | 
| 835 | 
            +
                  #       should have_many(:visitors).with_foreign_type('facility_type')
         | 
| 836 | 
            +
                  #     end
         | 
| 837 | 
            +
                  #
         | 
| 458 838 | 
             
                  # ##### dependent
         | 
| 459 839 | 
             
                  #
         | 
| 460 840 | 
             
                  # Use `dependent` to assert that the `:dependent` option was specified.
         | 
| @@ -726,6 +1106,24 @@ module Shoulda | |
| 726 1106 | 
             
                  #       should have_one(:job).with_foreign_key('worker_id')
         | 
| 727 1107 | 
             
                  #     end
         | 
| 728 1108 | 
             
                  #
         | 
| 1109 | 
            +
                  # ##### with_foreign_type
         | 
| 1110 | 
            +
                  #
         | 
| 1111 | 
            +
                  # Use `with_foreign_type` to test usage of the `:foreign_type` option.
         | 
| 1112 | 
            +
                  #
         | 
| 1113 | 
            +
                  #     class Hotel < ActiveRecord::Base
         | 
| 1114 | 
            +
                  #       has_one :special_guest, foreign_type: 'facility_type', as: :location
         | 
| 1115 | 
            +
                  #     end
         | 
| 1116 | 
            +
                  #
         | 
| 1117 | 
            +
                  #     # RSpec
         | 
| 1118 | 
            +
                  #     RSpec.describe Hotel, type: :model do
         | 
| 1119 | 
            +
                  #       it { should have_one(:special_guest).with_foreign_type('facility_type') }
         | 
| 1120 | 
            +
                  #     end
         | 
| 1121 | 
            +
                  #
         | 
| 1122 | 
            +
                  #     # Minitest (Shoulda)
         | 
| 1123 | 
            +
                  #     class HotelTest < ActiveSupport::TestCase
         | 
| 1124 | 
            +
                  #       should have_one(:special_guest).with_foreign_type('facility_type')
         | 
| 1125 | 
            +
                  #     end
         | 
| 1126 | 
            +
                  #
         | 
| 729 1127 | 
             
                  # ##### through
         | 
| 730 1128 | 
             
                  #
         | 
| 731 1129 | 
             
                  # Use `through` to test usage of the `:through` option. This asserts that
         | 
| @@ -1068,6 +1466,11 @@ module Shoulda | |
| 1068 1466 | 
             
                      self
         | 
| 1069 1467 | 
             
                    end
         | 
| 1070 1468 |  | 
| 1469 | 
            +
                    def types(types)
         | 
| 1470 | 
            +
                      @options[:types] = types
         | 
| 1471 | 
            +
                      self
         | 
| 1472 | 
            +
                    end
         | 
| 1473 | 
            +
             | 
| 1071 1474 | 
             
                    def autosave(autosave)
         | 
| 1072 1475 | 
             
                      @options[:autosave] = autosave
         | 
| 1073 1476 | 
             
                      self
         | 
| @@ -1088,11 +1491,21 @@ module Shoulda | |
| 1088 1491 | 
             
                      self
         | 
| 1089 1492 | 
             
                    end
         | 
| 1090 1493 |  | 
| 1494 | 
            +
                    def with_foreign_type(foreign_type)
         | 
| 1495 | 
            +
                      @options[:foreign_type] = foreign_type
         | 
| 1496 | 
            +
                      self
         | 
| 1497 | 
            +
                    end
         | 
| 1498 | 
            +
             | 
| 1091 1499 | 
             
                    def with_primary_key(primary_key)
         | 
| 1092 1500 | 
             
                      @options[:primary_key] = primary_key
         | 
| 1093 1501 | 
             
                      self
         | 
| 1094 1502 | 
             
                    end
         | 
| 1095 1503 |  | 
| 1504 | 
            +
                    def with_query_constraints(query_constraints)
         | 
| 1505 | 
            +
                      @options[:query_constraints] = query_constraints
         | 
| 1506 | 
            +
                      self
         | 
| 1507 | 
            +
                    end
         | 
| 1508 | 
            +
             | 
| 1096 1509 | 
             
                    def required(required = true)
         | 
| 1097 1510 | 
             
                      remove_submatcher(AssociationMatchers::OptionalMatcher)
         | 
| 1098 1511 | 
             
                      add_submatcher(
         | 
| @@ -1123,6 +1536,11 @@ module Shoulda | |
| 1123 1536 | 
             
                      self
         | 
| 1124 1537 | 
             
                    end
         | 
| 1125 1538 |  | 
| 1539 | 
            +
                    def strict_loading(strict_loading = true)
         | 
| 1540 | 
            +
                      @options[:strict_loading] = strict_loading
         | 
| 1541 | 
            +
                      self
         | 
| 1542 | 
            +
                    end
         | 
| 1543 | 
            +
             | 
| 1126 1544 | 
             
                    def join_table(join_table_name)
         | 
| 1127 1545 | 
             
                      @options[:join_table_name] = join_table_name
         | 
| 1128 1546 | 
             
                      self
         | 
| @@ -1155,8 +1573,10 @@ module Shoulda | |
| 1155 1573 | 
             
                        macro_correct? &&
         | 
| 1156 1574 | 
             
                        validate_inverse_of_through_association &&
         | 
| 1157 1575 | 
             
                        (polymorphic? || class_exists?) &&
         | 
| 1576 | 
            +
                        foreign_type_matches? &&
         | 
| 1158 1577 | 
             
                        foreign_key_exists? &&
         | 
| 1159 1578 | 
             
                        primary_key_exists? &&
         | 
| 1579 | 
            +
                        query_constraints_exists? &&
         | 
| 1160 1580 | 
             
                        class_name_correct? &&
         | 
| 1161 1581 | 
             
                        join_table_correct? &&
         | 
| 1162 1582 | 
             
                        autosave_correct? &&
         | 
| @@ -1164,6 +1584,8 @@ module Shoulda | |
| 1164 1584 | 
             
                        conditions_correct? &&
         | 
| 1165 1585 | 
             
                        validate_correct? &&
         | 
| 1166 1586 | 
             
                        touch_correct? &&
         | 
| 1587 | 
            +
                        types_correct? &&
         | 
| 1588 | 
            +
                        strict_loading_correct? &&
         | 
| 1167 1589 | 
             
                        submatchers_match?
         | 
| 1168 1590 | 
             
                    end
         | 
| 1169 1591 |  | 
| @@ -1258,29 +1680,65 @@ module Shoulda | |
| 1258 1680 | 
             
                      false
         | 
| 1259 1681 | 
             
                    end
         | 
| 1260 1682 |  | 
| 1261 | 
            -
                    def  | 
| 1262 | 
            -
                      macro == :belongs_to ||
         | 
| 1263 | 
            -
             | 
| 1683 | 
            +
                    def macro_is_not_through?
         | 
| 1684 | 
            +
                      macro == :belongs_to || has_association_not_through?
         | 
| 1685 | 
            +
                    end
         | 
| 1686 | 
            +
             | 
| 1687 | 
            +
                    def has_association_not_through?
         | 
| 1688 | 
            +
                      [:has_many, :has_one].include?(macro) && !through?
         | 
| 1264 1689 | 
             
                    end
         | 
| 1265 1690 |  | 
| 1266 1691 | 
             
                    def foreign_key_exists?
         | 
| 1267 1692 | 
             
                      !(belongs_foreign_key_missing? || has_foreign_key_missing?)
         | 
| 1268 1693 | 
             
                    end
         | 
| 1269 1694 |  | 
| 1695 | 
            +
                    def foreign_type_matches?
         | 
| 1696 | 
            +
                      !options.key?(:foreign_type) || (
         | 
| 1697 | 
            +
                        !belongs_foreign_type_missing? &&
         | 
| 1698 | 
            +
                        !has_foreign_type_missing?
         | 
| 1699 | 
            +
                      )
         | 
| 1700 | 
            +
                    end
         | 
| 1701 | 
            +
             | 
| 1270 1702 | 
             
                    def primary_key_exists?
         | 
| 1271 | 
            -
                      ! | 
| 1703 | 
            +
                      !macro_is_not_through? || primary_key_correct?(model_class)
         | 
| 1704 | 
            +
                    end
         | 
| 1705 | 
            +
             | 
| 1706 | 
            +
                    def query_constraints_exists?
         | 
| 1707 | 
            +
                      !macro_is_not_through? || query_constraints_correct?
         | 
| 1708 | 
            +
                    end
         | 
| 1709 | 
            +
             | 
| 1710 | 
            +
                    def query_constraints_correct?
         | 
| 1711 | 
            +
                      if options.key?(:query_constraints)
         | 
| 1712 | 
            +
                        if option_verifier.correct_for_string?(:query_constraints, options[:query_constraints])
         | 
| 1713 | 
            +
                          true
         | 
| 1714 | 
            +
                        else
         | 
| 1715 | 
            +
                          @missing = "#{model_class} should have \:query_constraints"\
         | 
| 1716 | 
            +
                          " options set to #{options[:query_constraints]}"
         | 
| 1717 | 
            +
                          false
         | 
| 1718 | 
            +
                        end
         | 
| 1719 | 
            +
                      else
         | 
| 1720 | 
            +
                        true
         | 
| 1721 | 
            +
                      end
         | 
| 1272 1722 | 
             
                    end
         | 
| 1273 1723 |  | 
| 1274 1724 | 
             
                    def belongs_foreign_key_missing?
         | 
| 1275 1725 | 
             
                      macro == :belongs_to && !class_has_foreign_key?(model_class)
         | 
| 1276 1726 | 
             
                    end
         | 
| 1277 1727 |  | 
| 1728 | 
            +
                    def belongs_foreign_type_missing?
         | 
| 1729 | 
            +
                      macro == :belongs_to && !class_has_foreign_type?(model_class)
         | 
| 1730 | 
            +
                    end
         | 
| 1731 | 
            +
             | 
| 1278 1732 | 
             
                    def has_foreign_key_missing?
         | 
| 1279 | 
            -
                       | 
| 1280 | 
            -
                        !through? &&
         | 
| 1733 | 
            +
                      has_association_not_through? &&
         | 
| 1281 1734 | 
             
                        !class_has_foreign_key?(associated_class)
         | 
| 1282 1735 | 
             
                    end
         | 
| 1283 1736 |  | 
| 1737 | 
            +
                    def has_foreign_type_missing?
         | 
| 1738 | 
            +
                      has_association_not_through? &&
         | 
| 1739 | 
            +
                        !class_has_foreign_type?(associated_class)
         | 
| 1740 | 
            +
                    end
         | 
| 1741 | 
            +
             | 
| 1284 1742 | 
             
                    def class_name_correct?
         | 
| 1285 1743 | 
             
                      if options.key?(:class_name)
         | 
| 1286 1744 | 
             
                        if option_verifier.correct_for_constant?(
         | 
| @@ -1299,10 +1757,7 @@ module Shoulda | |
| 1299 1757 | 
             
                    end
         | 
| 1300 1758 |  | 
| 1301 1759 | 
             
                    def join_table_correct?
         | 
| 1302 | 
            -
                      if (
         | 
| 1303 | 
            -
                        macro != :has_and_belongs_to_many ||
         | 
| 1304 | 
            -
                        join_table_matcher.matches?(@subject)
         | 
| 1305 | 
            -
                      )
         | 
| 1760 | 
            +
                      if macro != :has_and_belongs_to_many || join_table_matcher.matches?(@subject)
         | 
| 1306 1761 | 
             
                        true
         | 
| 1307 1762 | 
             
                      else
         | 
| 1308 1763 | 
             
                        @missing = join_table_matcher.failure_message
         | 
| @@ -1393,6 +1848,45 @@ module Shoulda | |
| 1393 1848 | 
             
                      end
         | 
| 1394 1849 | 
             
                    end
         | 
| 1395 1850 |  | 
| 1851 | 
            +
                    def types_correct?
         | 
| 1852 | 
            +
                      if options.key?(:types)
         | 
| 1853 | 
            +
                        types = options[:types]
         | 
| 1854 | 
            +
             | 
| 1855 | 
            +
                        correct = types.all? do |type|
         | 
| 1856 | 
            +
                          scope_name = type.tableize.tr('/', '_')
         | 
| 1857 | 
            +
                          singular   = scope_name.singularize
         | 
| 1858 | 
            +
                          query      = "#{singular}?"
         | 
| 1859 | 
            +
             | 
| 1860 | 
            +
                          Object.const_defined?(type) && @subject.respond_to?(query) &&
         | 
| 1861 | 
            +
                            @subject.respond_to?(singular)
         | 
| 1862 | 
            +
                        end
         | 
| 1863 | 
            +
             | 
| 1864 | 
            +
                        if correct
         | 
| 1865 | 
            +
                          true
         | 
| 1866 | 
            +
                        else
         | 
| 1867 | 
            +
                          @missing = "#{name} should have types: #{options[:types]}"
         | 
| 1868 | 
            +
                          false
         | 
| 1869 | 
            +
                        end
         | 
| 1870 | 
            +
                      else
         | 
| 1871 | 
            +
                        true
         | 
| 1872 | 
            +
                      end
         | 
| 1873 | 
            +
                    end
         | 
| 1874 | 
            +
             | 
| 1875 | 
            +
                    def strict_loading_correct?
         | 
| 1876 | 
            +
                      return true unless options.key?(:strict_loading)
         | 
| 1877 | 
            +
             | 
| 1878 | 
            +
                      if option_verifier.correct_for_boolean?(:strict_loading, options[:strict_loading])
         | 
| 1879 | 
            +
                        return true
         | 
| 1880 | 
            +
                      end
         | 
| 1881 | 
            +
             | 
| 1882 | 
            +
                      @missing = [
         | 
| 1883 | 
            +
                        "#{name} should have strict_loading set to ",
         | 
| 1884 | 
            +
                        options[:strict_loading].to_s,
         | 
| 1885 | 
            +
                      ].join
         | 
| 1886 | 
            +
             | 
| 1887 | 
            +
                      false
         | 
| 1888 | 
            +
                    end
         | 
| 1889 | 
            +
             | 
| 1396 1890 | 
             
                    def class_has_foreign_key?(klass)
         | 
| 1397 1891 | 
             
                      @missing = validate_foreign_key(klass)
         | 
| 1398 1892 |  | 
| @@ -1407,6 +1901,22 @@ module Shoulda | |
| 1407 1901 | 
             
                      end
         | 
| 1408 1902 | 
             
                    end
         | 
| 1409 1903 |  | 
| 1904 | 
            +
                    def class_has_foreign_type?(klass)
         | 
| 1905 | 
            +
                      if options.key?(:foreign_type) && !foreign_type_correct?
         | 
| 1906 | 
            +
                        @missing = foreign_type_failure_message(
         | 
| 1907 | 
            +
                          klass,
         | 
| 1908 | 
            +
                          options[:foreign_type],
         | 
| 1909 | 
            +
                        )
         | 
| 1910 | 
            +
             | 
| 1911 | 
            +
                        false
         | 
| 1912 | 
            +
                      elsif !has_column?(klass, foreign_type)
         | 
| 1913 | 
            +
                        @missing = foreign_type_failure_message(klass, foreign_type)
         | 
| 1914 | 
            +
                        false
         | 
| 1915 | 
            +
                      else
         | 
| 1916 | 
            +
                        true
         | 
| 1917 | 
            +
                      end
         | 
| 1918 | 
            +
                    end
         | 
| 1919 | 
            +
             | 
| 1410 1920 | 
             
                    def has_column?(klass, column)
         | 
| 1411 1921 | 
             
                      case column
         | 
| 1412 1922 | 
             
                      when Array
         | 
| @@ -1423,10 +1933,21 @@ module Shoulda | |
| 1423 1933 | 
             
                      )
         | 
| 1424 1934 | 
             
                    end
         | 
| 1425 1935 |  | 
| 1936 | 
            +
                    def foreign_type_correct?
         | 
| 1937 | 
            +
                      option_verifier.correct_for_string?(
         | 
| 1938 | 
            +
                        :foreign_type,
         | 
| 1939 | 
            +
                        options[:foreign_type],
         | 
| 1940 | 
            +
                      )
         | 
| 1941 | 
            +
                    end
         | 
| 1942 | 
            +
             | 
| 1426 1943 | 
             
                    def foreign_key_failure_message(klass, foreign_key)
         | 
| 1427 1944 | 
             
                      "#{klass} does not have a #{foreign_key} foreign key."
         | 
| 1428 1945 | 
             
                    end
         | 
| 1429 1946 |  | 
| 1947 | 
            +
                    def foreign_type_failure_message(klass, foreign_type)
         | 
| 1948 | 
            +
                      "#{klass} does not have a #{foreign_type} foreign type."
         | 
| 1949 | 
            +
                    end
         | 
| 1950 | 
            +
             | 
| 1430 1951 | 
             
                    def primary_key_correct?(klass)
         | 
| 1431 1952 | 
             
                      if options.key?(:primary_key)
         | 
| 1432 1953 | 
             
                        if option_verifier.correct_for_string?(
         | 
| @@ -1457,11 +1978,10 @@ module Shoulda | |
| 1457 1978 | 
             
                    end
         | 
| 1458 1979 |  | 
| 1459 1980 | 
             
                    def foreign_key_reflection
         | 
| 1460 | 
            -
                      if (
         | 
| 1461 | 
            -
             | 
| 1462 | 
            -
             | 
| 1463 | 
            -
             | 
| 1464 | 
            -
                      )
         | 
| 1981 | 
            +
                      if [:has_one, :has_many].include?(macro) &&
         | 
| 1982 | 
            +
                         reflection.options.include?(:inverse_of) &&
         | 
| 1983 | 
            +
                         reflection.options[:inverse_of] != false
         | 
| 1984 | 
            +
             | 
| 1465 1985 | 
             
                        associated_class.reflect_on_association(
         | 
| 1466 1986 | 
             
                          reflection.options[:inverse_of],
         | 
| 1467 1987 | 
             
                        )
         | 
| @@ -1470,6 +1990,14 @@ module Shoulda | |
| 1470 1990 | 
             
                      end
         | 
| 1471 1991 | 
             
                    end
         | 
| 1472 1992 |  | 
| 1993 | 
            +
                    def foreign_type
         | 
| 1994 | 
            +
                      if [:has_one, :has_many].include?(macro)
         | 
| 1995 | 
            +
                        reflection.type
         | 
| 1996 | 
            +
                      else
         | 
| 1997 | 
            +
                        reflection.foreign_type
         | 
| 1998 | 
            +
                      end
         | 
| 1999 | 
            +
                    end
         | 
| 2000 | 
            +
             | 
| 1473 2001 | 
             
                    def submatchers_match?
         | 
| 1474 2002 | 
             
                      failing_submatchers.empty?
         | 
| 1475 2003 | 
             
                    end
         |