It requires two arguments, hence it should be 2?
Or if we call this method with one argument, the error message says "wrong number of arguments (given 1, expected 0; required keywords: a, b) (ArgumentError)", which means the arity is 0, maybe?
kwargs are... complicated. Let me first extend the issue with additional versions of the above (I run Ruby 3.1, but from what I know, everything applies to anything >= Ruby 3.0):
So, basically, how I understand the kwargs: they are actually internally the last Hash argument of a function (that is passed with a special flag). If all kwargs are optional, then it's an optional argument (so arity is -1).
They are unlike how blocks work - it's not a separate category of arguments.
If a function is declared with kwargs arguments special syntax (later I will call it a kwargs-syntax function), then this flag is enforced while checking arity (since Ruby 3.0 I believe). But otherwise, it's not, and kwargs are just passed as a simple argument:
It is possible to call a kwargs-syntax function with a non-kwargs Hash argument (but only with restarg syntax), if we set a flag (a distinct one, from what I understand) using Hash.ruby2_keywords_hash.
I would guess because f({a:1,b:2}) used to work before 3.0 and it was passing "one argument", hence arity 1.
Also def m(*); end can be called like m(a:1,b:2) and that's clearly one argument on the callee side.
So from the caller point of view kwargs are at most 1 argument.
In general it seems kwargs are considered as 0 (if all optional) or 1 "argument" (from a positional sense), which stems from that history.
💡 In case it helps -- regarding the mention of method parameters above -- I've found it easy to forget how method parameters work so wrote up an entire article on usage. I also find parameters more easy to reason about than arity (despite being less performant).