Type signature for a method that can take a hash or keyword arguments in RBS

I'm trying to add type check support in RBS for the following method:

      def create_bridge(caps:, url:, http_client: nil)
        Remote::Bridge.new(http_client: http_client, url: url).tap do |bridge|
          bridge.create_session(caps)
        end
      end

This method can be call in the following way:

      def initialize(bridge: nil, listener: nil, **opts)
        @devtools = nil
        @bidi = nil
        bridge ||= create_bridge(**opts)
        add_extensions(bridge.browser)
        @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
      end

And I declared it on RBS as:

def create_bridge: (caps: untyped?, url: untyped?, http_client: untyped? ) -> untyped

Which results on the following error when I run steep:

lib/selenium/webdriver/common/driver.rb:74:19: [error] More keyword arguments are required: caps, url, http_client
│ Diagnostic ID: Ruby::InsufficientKeywordArguments
│
└         bridge ||= create_bridge(**opts)
                     ~~~~~~~~~~~~~~~~~~~~~

However, if I try to make all the keywords optional, I face the following errors:

lib/selenium/webdriver/common/driver.rb:315:24: [error] The method parameter is incompatible with the declaration `(?caps: untyped, ?url: untyped, ?http_client: untyped) -> untyped`
│ Diagnostic ID: Ruby::MethodParameterMismatch
│
└       def create_bridge(caps:, url:, http_client: nil)
                          ~~~~~

lib/selenium/webdriver/common/driver.rb:315:31: [error] The method parameter is incompatible with the declaration `(?caps: untyped, ?url: untyped, ?http_client: untyped) -> untyped`
│ Diagnostic ID: Ruby::MethodParameterMismatch
│
└       def create_bridge(caps:, url:, http_client: nil)

It is the same if I try to overload the method definition

Could you tell me the best approach to add the correct type signature?

Thank you very much for the time

Upvotes: 0

Views: 95

Answers (2)

In case someone is not using ruby 3.1 or above the following option also makes the trick

  def initialize(bridge: nil, listener: nil, **opts)
    @devtools = nil
    @bidi = nil
    bridge ||= create_bridge(caps: opts[:caps], url: opts[:url], http_client: opts[:http_client])
    add_extensions(bridge.browser)
    @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
  end

Upvotes: 0

Chiperific
Chiperific

Reputation: 4696

What about assigning the values in initialize?

      def initialize(bridge: nil, listener: nil, **opts)
        @devtools = nil
        @bidi = nil
        caps = opts[:caps]                   # or handle nil case
        url = opts[:url]                     # or handle nil case
        http_client = opts[:http_client]     # or handle nil case
        bridge ||= create_bridge(caps:, url:, http_client:) # explicitly pass attributes
        add_extensions(bridge.browser)
        @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
      end

Upvotes: 2

Related Questions