# Method Arguments and Conventions — Ruby

Source: https://www.geekswithgeeks.com/en/ruby/m-args

> Use positional, optional, keyword and splat arguments, and follow naming conventions.

## Flexible method signatures

Ruby methods accept **required positional** arguments, **optional** ones with defaults (`def greet(name, greeting = "Hello")`), a **splat** `*args` collecting extra positional arguments into an array, **keyword arguments** (`def connect(host:, port: 443)`, where `host:` without a default is required), a **double splat** `**opts` collecting extra keywords into a hash, and a **block** parameter `&block`. Ruby 3 separates positional and keyword arguments strictly, so passing a hash where keywords are expected requires `**hash`. Use **keyword arguments** for anything optional or easily confused, such as booleans and units. Methods return the value of their last expression, and `return` is used mainly for early exits. Naming conventions carry meaning: **`?`** for predicates returning booleans (`empty?`, `valid?`), **`!`** for dangerous versions of a method that mutate or raise (`save!`, `sort!`), and **`=`** for setters (`name=`). Argument forwarding `(...)` passes all arguments through, handy in wrappers and decorators.

## Kinds of method parameters

Positional, optional, splat, keyword, double splat and block parameters, in that order.

![A method box with input slots of different styles arranged left to right, the last one shaped like a small code block.](assets/figures/ruby/section-4-map.svg) — Figure 4.1 — Ruby method parameter kinds.

## Keyword arguments, splats and forwarding

Readable calls and safe defaults.

```ruby
def send_invoice(invoice, to:, cc: [], urgent: false, **headers)
  subject = urgent ? "URGENT: #{invoice}" : invoice.to_s
  puts "To #{to} (cc #{cc.join(', ')}): #{subject} #{headers}"
end

send_invoice("INV-7", to: "asha@example.com", urgent: true, reply_to: "billing@example.com")

def total(*amounts, discount: 0)
  amounts.sum * (1 - discount)
end
puts total(100, 250, 50, discount: 0.1)    # 360.0

options = { to: "ravi@example.com", cc: ["ops@example.com"] }
send_invoice("INV-8", **options)            # pass a hash as keywords explicitly

def logged_send(...)                         # forward all arguments and the block
  puts "sending..."
  send_invoice(...)
end
logged_send("INV-9", to: "meera@example.com")
```

## Keywords for booleans

`ship(order, true, false)` is a puzzle. `ship(order, express: true, gift_wrap: false)` explains itself and cannot mix up the two flags.

**Quiz:** In `def connect(host:, port: 443)`, which statement is true?

- [ ] Both are optional
- [ ] host is positional
- [x] host is a required keyword argument; port is optional with a default
- [ ] It is a syntax error

*Answer:* host is a required keyword argument; port is optional with a default. A keyword without a default value is required.
