Functions in Ruby
Learn how to define and use methods in Ruby—parameters, default and keyword arguments, scope, recursion, and blocks, procs, and lambdas—with Docker-ready examples
In Ruby, the unit of reusable behavior is the method. Because everything in Ruby is an object, what other languages call a “free function” is really a method defined on an object—and a method defined at the top level of a file becomes a private method on Object, callable from anywhere. Ruby leans on this object model rather than a separate notion of standalone functions.
Ruby is multi-paradigm, blending object-oriented, functional, and imperative styles. That shows up clearly in how it handles reusable behavior: you get classic named methods with parameters and return values, but you also get blocks, procs, and lambdas—first-class chunks of code you can pass around, store in variables, and call later. This functional capability is what powers Ruby’s famously expressive iterators like each, map, and select.
This tutorial covers defining and calling methods, working with positional, default, keyword, and variable-length arguments, how Ruby handles return values and scope, writing recursive methods, and using blocks, procs, and lambdas as first-class code objects.
Defining and Calling Methods
A method is defined with the def keyword and closed with end. Ruby has an implicit return: the value of the last expression evaluated is returned automatically, so an explicit return is usually optional.
Create a file named functions.rb:
| |
Calling a method does not require parentheses, though they improve clarity when arguments are passed. Note return -n if n < 0—Ruby’s trailing if modifier lets you guard an early return on a single, readable line.
Default and Keyword Arguments
Ruby supports default parameter values so callers can omit arguments. It also supports keyword arguments, where parameters are named at the call site, making calls self-documenting and order-independent.
Create a file named arguments.rb:
| |
Keyword arguments declared with a trailing colon (name:) and no default are required; Ruby raises an error if they are missing. Those with a value (role: "developer") are optional. String interpolation with #{...} embeds the argument values directly into the result.
Variable-Length Arguments
Ruby can collect an arbitrary number of arguments using the splat operator (*) for positional arguments and the double splat (**) for keyword arguments. This is how methods like puts accept any number of values.
Create a file named splat_args.rb:
| |
Inside sum, numbers is a regular Array, so all of Ruby’s array methods are available—here reduce folds the values into a single total. Inside configure, options is a Hash. These collection methods take a block (the { ... } part), which we explore below.
Scope and Recursion
Ruby method definitions create a new local scope. Local variables from outside a method are not visible inside it—Ruby deliberately isolates methods to avoid surprising action at a distance. Recursion, where a method calls itself, works naturally for problems with a self-similar structure.
Create a file named scope_recursion.rb:
| |
The two message variables are completely independent because the method has its own scope. The factorial method recurses until it hits the base case n <= 1, and fib sums the two preceding values until n is below 2.
Blocks, Procs, and Lambdas
Here is where Ruby’s functional side shines. A block is an anonymous chunk of code passed to a method, written with do...end or {...}. A method can run the block with yield. For storing code in a variable and passing it around, Ruby offers procs and lambdas—both are objects you call with .call.
Create a file named higher_order.rb:
| |
The repeat method uses yield to invoke whatever block the caller provides. The lambda ->(x) { x * x } is Ruby’s compact arrow syntax for an anonymous function. Prefixing a parameter with & converts a block to a proc object (and vice versa), which is how apply_twice receives and calls it. Methods like map and select are themselves block-taking methods—this is everyday functional programming in Ruby.
Running with Docker
Run each example using the official Ruby Alpine image—no local Ruby installation needed.
| |
Expected Output
Running functions.rb:
Hello from Ruby!
7
15
15
Running arguments.rb:
25
1024
Matz is a creator
Alice is a maintainer
Bob is a developer
Running splat_args.rb:
6
150
0
host=localhost, port=3000, ssl=true
Running scope_recursion.rb:
inner scope
outer scope
120
55
Running higher_order.rb:
Iteration 1
Iteration 2
Iteration 3
36
81
[2, 4, 6, 8]
[2, 4, 6]
Key Concepts
- Implicit return — A method returns the value of its last evaluated expression; an explicit
returnis only needed to exit early. - Flexible arguments — Ruby supports positional, default, and keyword arguments, plus the splat (
*) and double-splat (**) operators to collect variable-length arguments into an array or hash. - Keyword arguments are self-documenting — Named arguments make call sites readable and order-independent; those without defaults are required.
- Methods have isolated scope — A method cannot see outer local variables, which prevents accidental shared state and surprising side effects.
- Recursion is natural — With a clear base case, methods can call themselves to solve self-similar problems like factorial and Fibonacci.
- Code is a first-class value — Blocks, procs, and lambdas let you pass behavior around.
yieldruns a block,&converts between blocks and proc objects, and.callinvokes a stored callable. - Functional iterators — Built-in methods like
map,select, andreducetake blocks, making functional-style data transformation idiomatic everyday Ruby.
Comments
Loading comments...
Leave a Comment