[ruby-talk:444215] Is this the correct behaviour of `super`

I have been investigating a test failure triggered by upgrading selenium-webdriver from v4.9.0 to v4.9.1. This has lead me to produce the following test code that demonstrates the problem which occurs as an interaction between capybara and selenium. The test produces the following error

wrong number of arguments (given 2, expected 0..1) (ArgumentError)

Here is some code that reproduces the error

-----8<-----8<-----8<-----8<-----8<-----8<------8<-----8<-----8<-----
require 'selenium/webdriver/atoms'
require 'selenium/webdriver/common'
require 'selenium/webdriver/version'

module DeprecationSuppressor
  def initialize(*)
    puts 'in DeprecationSuppressor::initialize'
    super
  end
end
Selenium::WebDriver::Logger.prepend DeprecationSuppressor

class Demo
  def initialize
    @logger = Selenium::WebDriver::Logger.new('Selenium', ignored: true)
    puts @logger.class
  end
end

Demo.new
-----8<-----8<-----8<-----8<-----8<-----8<------8<-----8<-----8<-----

Here is it failing

➜ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
➜ ruby demo.rb
in DeprecationSuppressor::initialize
/Users/my/.rvm/gems/ruby-3.2.2@test/gems/selenium-webdriver-4.9.1/lib/selenium/webdriver/common/logger.rb:51:in `initialize': wrong number of arguments (given 2, expected 0..1) (ArgumentError)

The error is raised by the `super` call in the initialize method of the DeprecationSuppressor module.

Naming the arguments in the initialize method fixes the problem
e.g.

-----8<-----8<-----8<-----8<-----8<-----8<------8<-----8<-----8<-----
module DeprecationSuppressor
  def initialize(*args)
    puts 'in DeprecationSuppressor::initialize'
    super args
  end
end
Selenium::WebDriver::Logger.prepend DeprecationSuppressor
-----8<-----8<-----8<-----8<-----8<-----8<------8<-----8<-----8<-----

➜ ruby demo.rb
in DeprecationSuppressor::initialize
Selenium::WebDriver::Logger

I have also found that using `initialize(...)` works too.

I've tested this on Ruby 3.2.2 and 3.1.4

For further context of the wider problem, here is the initialize method in selenium-webdriver 4.9.0 and 4.9.1
4.9.0: https://github.com/SeleniumHQ/selenium/blob/selenium-4.9.0/rb/lib/selenium/webdriver/common/logger.rb#L51
4.9.1: https://github.com/SeleniumHQ/selenium/blob/selenium-4.9.1/rb/lib/selenium/webdriver/common/logger.rb#L51
The difference being that two more named arguments have been added

Finally it looks to me as though the Capybara team are preparing to fix this in v3.9.1 (ArgumentError: wrong number of arguments (given 2, expected 0..1) · Issue #2666 · teamcapybara/capybara · GitHub)

My question is whether Ruby is behaving correctly? It seems to me that the `super` call in the initialize(*) method should work.

···

______________________________________________
ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org
To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org
ruby-talk info -- Info | ruby-talk@ml.ruby-lang.org - ml.ruby-lang.org

wrong number of arguments (given 2, expected 0..1) (ArgumentError)

Here is some code that reproduces the error

module DeprecationSuppressor
def initialize(*)
   puts 'in DeprecationSuppressor::initialize'
   super
end
end
Selenium::WebDriver::Logger.prepend DeprecationSuppressor

'In Ruby 3.0, positional arguments and keyword arguments will be separated. ... In Ruby 3, a method delegating all arguments must explicitly delegate keyword arguments in addition to positional arguments. ... So when you want to pass keyword arguments, you should always use foo(k: expr) or foo(**expr). If you want to accept keyword arguments, in principle you should always use def foo(k: default) or def foo(k:) or def foo(**kwargs). ... Alternatively, if you do not need compatibility with Ruby 2.6 or prior and you don’t alter any arguments, you can use the new delegation syntax (...) that is introduced in Ruby 2.7."

https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/

···

______________________________________________
ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org
To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org
ruby-talk info -- Info | ruby-talk@ml.ruby-lang.org - ml.ruby-lang.org

"""
So when you want to pass keyword arguments, you should always use foo(k:
expr) or foo(**expr). If you want to accept keyword arguments, in principle
you should always use def foo(k: default) or def foo(k:) or def
foo(**kwargs).
"""

Isn't `**expr` same with `**kwargs`?

···

On Mon, May 15, 2023, 01:57 Frank J. Cameron via ruby-talk < ruby-talk@ml.ruby-lang.org> wrote:

>> wrong number of arguments (given 2, expected 0..1) (ArgumentError)
>
>Here is some code that reproduces the error
>
>module DeprecationSuppressor
> def initialize(*)
> puts 'in DeprecationSuppressor::initialize'
> super
> end
>end
>Selenium::WebDriver::Logger.prepend DeprecationSuppressor

'In Ruby 3.0, positional arguments and keyword arguments will be
separated. ... In Ruby 3, a method delegating all arguments must explicitly
delegate keyword arguments in addition to positional arguments. ... So when
you want to pass keyword arguments, you should always use foo(k: expr) or
foo(**expr). If you want to accept keyword arguments, in principle you
should always use def foo(k: default) or def foo(k:) or def foo(**kwargs).
... Alternatively, if you do not need compatibility with Ruby 2.6 or prior
and you don’t alter any arguments, you can use the new delegation syntax
(...) that is introduced in Ruby 2.7."

Separation of positional and keyword arguments in Ruby 3.0

______________________________________________
ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org
To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org
ruby-talk info --
Info | ruby-talk@ml.ruby-lang.org - ml.ruby-lang.org