This episode dissects Ruby methods: positional parameters, default values, keyword arguments, splats, and implicit return, then blocks, Proc, and Lambda with their differences, the it and _1 block parameters, and the map, select, and reduce Enumerable methods with chaining.

After mastering syntax and control flow, it's time to shape reusable logic units: methods. But Ruby doesn't stop at ordinary methods. The language makes blocks first-class citizens, so you can insert pieces of logic into other methods — this is what makes Ruby code so expressive.
This episode 5 dissects three interrelated concepts: method definitions with all their parameter styles, blocks along with yield, and Proc vs Lambda with their often-tricky behavioral differences. At the end, you'll get to know Enumerable — the module that provides map, select, and reduce — the core of Ruby's functional programming style.
Methods are defined with def and closed with end. Method names can end in ? (boolean predicates) or ! (mutation). Positional parameters accept arguments in order, and parameters with default values can be omitted when calling:
def sapa(nama, salam = "Halo")
"#{salam}, #{nama}!"
end
puts sapa("Arman")
puts sapa("Ruby", "Selamat datang")The code block above displays Halo, Arman! and Selamat datang, Ruby!. Note the implicit return: the value of the last expression (the interpolated string) automatically becomes the method's return value, without a return keyword. The call sapa("Arman") uses the default "Halo", while sapa("Ruby", "Selamat datang") overrides its value.
Ruby supports keyword arguments, which are order-independent, and splats to capture an indefinite number of arguments. The * sign captures positional arguments into an array, and ** captures keywords into a hash:
def buat_pengguna(nama:, umur:, role: "user")
"#{role}: #{nama} (#{umur})"
end
puts buat_pengguna(nama: "Arman", umur: 30)
def total(*angka)
angka.sum
end
puts total(1, 2, 3, 4)The call buat_pengguna(nama: "Arman", umur: 30) uses the required keywords nama and umur, while role is optional. The method total(*angka) accepts many positional arguments that get combined into an array, then sums them. Both styles are very common in Rails and well-known gems.
A block is a piece of code passed to a method and executed inside it. There are two forms: do...end for multi-line blocks and { } for single-line ones. The convention: use { } for blocks whose result is reused (like map), and do...end for blocks that perform side effects (like each).
A method calls the given block through the yield keyword. If you want to treat the block as an object, capture it with the &block parameter:
def ulang_kali
yield
yield
end
ulang_kali { puts "block dipanggil" }yield executes the block twice, so block dipanggil is printed twice. Blocks can also accept arguments: yield(3) will pass 3 to the block parameter like { |n| ... }. This pattern is the basis of the iterators you'll use over and over.
Proc and Lambda both represent a block as an object, but their behavior differs in two important ways: how they handle return and how they handle argument counts. Lambdas are strict like regular methods, while Procs are loose. Look at the return difference:
def coba_proc
p = proc { return "return dari proc" }
p.call
"tidak tercapai"
end
puts coba_proc
def coba_lambda
l = -> { return "return dari lambda" }
l.call
"setelah lambda"
end
puts coba_lambdacoba_proc displays return dari proc because return inside a Proc exits its enclosing method. Conversely, coba_lambda displays setelah lambda — return inside a Lambda only exits the Lambda itself. p.call executes the Proc, while l.call executes the Lambda.
Since Ruby 3.4, blocks can use an implicit parameter named it, replacing _1 (the numbered parameter from Ruby 2.7):
puts [1, 2, 3].map { _1 * 2 }
puts [1, 2, 3].map { it * 2 }
puts [1, 2, 3].map { |n| n * 2 }All three lines produce [2, 4, 6]. it is only available when the block doesn't declare an explicit parameter. map { it * 2 } is easier to read than _1, and this style is the recommendation for Ruby 4.0 code.
The Enumerable module gives arrays and hashes the power of data transformation. map transforms every element, select filters based on a condition, and reduce accumulates values. All three return new arrays without modifying the original data:
angka = [1, 2, 3, 4, 5, 6]
hasil = angka.select { |n| n.even? }
.map { |n| n * 10 }
puts hasil.inspectThe block above filters even numbers, then multiplies by ten, producing [20, 40, 60]. reduce, for example angka.reduce(0) { |jumlah, n| jumlah + n }, sums all elements — the equivalent of angka.sum. The power of chaining shows when operations are strung together one after another.
Because every transformation returns a new collection, you can chain them endlessly. This is a very Rails-friendly style: take data, filter, transform, then accumulate in a single chain. each_with_index provides a sequence number during iteration. More detail on Enumerator and lazy evaluation will be covered in episode 10.
Warning
Don't mix Proc with Lambda without understanding the return difference. In Rails and other frameworks, converting a block to the wrong kind of object can cause hard-to-trace bugs, such as exiting a method too early.
Episode 5 unlocks Ruby's expressive power: methods with implicit return, default parameters, keyword arguments, and splats, blocks with yield, the difference between Proc and Lambda, the it block parameter since Ruby 3.4, and chainable Enumerable methods like map, select, and reduce.
Key takeaways:
*args captures positional arguments, **kwargs captures keyword arguments.yield executes a block; &block captures it as an object.return in a Proc exits the enclosing method; in a Lambda it only exits the Lambda.it is the implicit block parameter since Ruby 3.4, replacing _1.map, select, and reduce return new data and can be chained.In the next episode, episode 6, we will discuss OOP: class, object, and module — initialize, instance methods and class methods, attr_accessor, inheritance, modules with include, extend, and prepend, the built-in Comparable and Enumerable modules, and public, protected, and private visibility. This is the core of the Ruby paradigm.