Skip to content

Contract error when mixing positional and keyword arguments with defaults #304

@vlad-pisanov

Description

@vlad-pisanov

I'm having trouble defining a contract for a method that takes two optional arguments -- a positional one and a keyword one. Consider:

class C
  include Contracts

  Contract String, KeywordArgs[b: Optional[String]] => Any
  def foo(a = 'a', b: 'b')
    p [a, b]
  end
end

c = C.new
c.foo('a', b: 'b') # Works ✔️
c.foo('a')         # Works ✔️
c.foo(b: 'b')      # Contract error ❌
c.foo              # Contract error ❌

The stack trace is

Contract violation for argument 1 of 1: (ParamContractError)
        Expected: String,
        Actual: {:b=>"b"}
        Value guarded in: C::foo
        With Contract: String, KeywordArgs => Any
        At: c.rb:9

      fail data[:contracts].failure_exception.new(failure_msg(data), data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        from /Users/main/.gem/ruby/3.3.2/gems/contracts-0.17/lib/contracts.rb:197:in `failure_callback'
        from /Users/main/.gem/ruby/3.3.2/gems/contracts-0.17/lib/contracts/method_handler.rb:144:in `block in redefine_method'

It seems Contracts wants me to provide the positional argument even if a default is specified in the method signature? 🤔

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions