Skip to content

Commit 3d0ced6

Browse files
authored
Merge pull request #5801 from DataDog/doc-delegation
Add documentation about the correct delegation pattern
2 parents 40a97bb + 53ffb69 commit 3d0ced6

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

docs/Delegation.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Delegation
2+
3+
Correct delegation of positional and keyword arguments is tricky, especially when supporting down to Ruby 2.5.
4+
5+
This is the delegation pattern we use, which is correct for all Ruby versions:
6+
7+
```ruby
8+
# The One and Only Correct Delegation Pattern
9+
if RUBY_VERSION >= '3'
10+
def foo(*args, **kwargs, &block) # steep:ignore DifferentMethodParameterKind
11+
bar(*args, **kwargs, &block)
12+
end
13+
else
14+
def foo(*args, &block)
15+
bar(*args, &block)
16+
end
17+
ruby2_keywords :foo if respond_to?(:ruby2_keywords, true)
18+
end
19+
```
20+
21+
We have to use `ruby2_keywords` because that's [the only way](https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html) to achieve correct delegation on Ruby 2.7.
22+
We otherwise avoid it (it's not defined on Ruby < 2.7 or it's noop) because it seems a bad idea to use a method named `ruby2*` on Ruby 3+.
23+
24+
An alternative is to use `(...)` on >= 2.7 and `(*args)` on < 2.7, but this requires `class_eval` because `(...)` is invalid syntax for < 2.7:
25+
```ruby
26+
args = RUBY_VERSION >= '2.7' ? '...' : '*args, &block'
27+
class_eval <<~RUBY
28+
def foo(#{args})
29+
bar(#{args})
30+
end
31+
RUBY
32+
```
33+
34+
To test that the delegation is correct, see commit `89d9fef36a6b894b039bc1d9ef6ed0af2c7a92bb`.
35+
36+
More details on this in [this blog post from Benoit](https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html) and [this ruby-lang.org article](https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/).

0 commit comments

Comments
 (0)