Ruby supports more than three kinds of arguments. The useful mental model is: positional arguments, keyword arguments, collection arguments, and blocks.
Required and optional positional arguments
1 | def greet(name, punctuation = "!") |
name is required; punctuation has a default. Missing a required argument or passing too many positional arguments raises ArgumentError.
Collecting positional arguments with splat
1 | def greet_all(*names) |
*names collects remaining positional arguments into an array. It is not really an “optional argument”; it is a rest parameter.
Keyword arguments
1 | def profile(name:, age: nil) |
name: is required, while age: nil is optional. Modern Ruby treats keyword arguments separately from a positional hash, so do not assume a hash will always be converted automatically.
Collect extra keywords with **:
1 | def request(method:, path:, **options) |
Blocks
Methods can receive behavior as well as values:
1 | def with_timing |
Use &block only when the block must be stored, forwarded, or called explicitly. Otherwise yield is simpler and avoids creating an unnecessary Proc object.
Ordering
A readable method usually follows this order:
1 | def example(required, optional = nil, *rest, keyword:, **options, &block) |
Ruby allows expressive APIs, but flexibility is not permission to make callers solve a puzzle. If a signature needs a documentary, an options object may be the kinder interface.