Methods
13.1 Defining Methods
def greet(name)
"Hello, #{name}!" # implicit return
end
def full_name(first, last) = "#{first} #{last}" # endless method (Ruby 3.0+)
def divide(a, b)
return nil if b.zero? # early return
a.to_f / b
end
def min_max(values)
[values.min, values.max] # "multiple return values" (an array)
end
lo, hi = min_max([3, 1, 9])13.2 Parameter Types
Ruby 3.0+ separates positional and keyword arguments strictly: hashes aren't implicitly converted to keywords.
def method_with_all(required, # positional
optional = "default", # optional positional
*rest, # splat: extra positionals as an array
keyword:, # required keyword
opt_kw: 10, # optional keyword
**options, # double splat: extra keywords as a hash
&block) # explicit block
end
def create_user(name:, email:, role: "member", **extra)
{ name:, email:, role:, **extra }
end
create_user(name: "Ana", email: "[email protected]", admin: true)
def sum(*numbers) = numbers.sum
sum(1, 2, 3)
sum(*[4, 5, 6]) # splat an array into arguments
opts = { name: "Bo", email: "[email protected]" }
create_user(**opts) # double splat a hash into keywords
def forward_all(...) = target(...) # argument forwarding (Ruby 2.7+)
def forward_rest(*, **, &) = target(*, **, &) # anonymous forwarding (Ruby 3.2+)13.3 Method Naming Conventions
def empty? = items.none? # predicate: returns a boolean
def sort! = items.sort! # bang: mutates or raises (has a non-bang counterpart)
def name=(value) # setter
@name = value.strip
end
def [](index) = items[index] # operator methods
def +(other) = Money.new(amount + other.amount)
def to_s = "Money(#{amount})" # conversion conventions: to_s, to_a, to_h, to_i, to_proc13.4 Method Objects and Introspection
m = "hello".method(:upcase)
m.call # "HELLO"
m.arity; m.owner; m.parameters
[1, 2, 3].map(&method(:puts))
5.respond_to?(:+)
Integer.instance_methods(false)
obj.public_methods.grep(/name/)
method(:greet).source_location13.5 Recursion
Ruby doesn't guarantee tail-call optimization (it's disabled by default). Deep recursion raises SystemStackError.
def factorial(n) = n <= 1 ? 1 : n * factorial(n - 1)
def fib(n, memo = {})
return n if n < 2
memo[n] ||= fib(n - 1, memo) + fib(n - 2, memo)
end