tupl-tufts / rdl

Types, type checking, and contracts for Ruby
BSD 3-Clause "New" or "Revised" License
602 stars 38 forks source link

Rails: class_name can be a class #58

Closed ainar-g closed 5 years ago

ainar-g commented 7 years ago

Steps for reproduction:

  1. Create an empty rails application with rails new foo

  2. Create two models:

    class A < ActiveRecord::Base
      has_many :bs, class_name: B
    end
    class B < ActiveRecord::Base
      belongs_to :a, class_name: A
    end
  3. Create a test:

    require 'test_helper'
    
    class ATest < ActiveSupport::TestCase
      test "one" do
        a = A.new
        assert a
      end
    end
  4. Configure RDL:

    RDL.config { |config|
      config.type_defaults = { wrap: true, typecheck: :now }
    }
  5. rake

Result:

  1) Error:
ATest#test_one:
RDL::Type::TypeError: ActiveRecord::Associations::ClassMethods#has_many: Argument type error.
Method type:
        (Symbol or String name, ?{ (?ActiveRecord::Base) -> %any } scope, { class_name: ?(Symbol or String), foreign_key: ?(Symbol or String), foreign_type: ?(Symbol or String), primary_key: ?(Symbol or String), dependent: ?(:delete_all or :restrict_with_error or :restrict_with_exception or :nullify or :destroy), counter_cache: ?(false or true or Symbol or String), as: ?(Symbol or String), through: ?(Symbol or String), source: ?(Symbol or String), source_type: ?(Symbol or String), validate: ?(false or true), inverse_of: ?(Symbol or String), extend: ?(Array<Module> or Module) }) ?{ () -> %any } -> %any
Actual argument types:
        (Symbol, Hash) 
Actual argument values (one per line):
        :bs
        {:class_name=>B(id: integer, a_id: integer)}

    app/models/a.rb:2:in `<class:A>'
    app/models/a.rb:1:in `<top (required)>'
    test/models/a_test.rb:5:in `block in <class:ATest>'

1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

I guess types for associations should include Class.

mckaz commented 5 years ago

Thanks! This is fixed in dev and will be merged into master shortly.