Blok (block) adalah potongan kode yang diserahkan kepada pemanggilan metode untuk dijalankan oleh metode penerimanya. Hampir semua kode Ruby bergantung pada blok, mulai dari iterator each dan map pada koleksi hingga perulangan loop. Topik ini membahas dua bentuk penulisan blok, mekanika kata kunci yield yang menjalankannya, cara blok menerima nilai melalui argumen berbentuk |x|, serta sifat blok yang membaca variabel di lingkungannya. Setelah membacanya, setiap pemanggilan metode yang menyertakan blok pada kode sehari-hari dapat diurai lengkap dengan alur kendalinya.
Dua bentuk penulisan blok#
Blok ditulis dalam dua bentuk, yaitu di antara do dan end atau di antara sepasang kurung kurawal { }. Keduanya berperilaku sama dan dapat digunakan pada metode mana pun yang menerima blok. Konvensi penulisan yang lazim menggunakan kurung kurawal untuk blok satu baris, sedangkan do ... end digunakan untuk blok yang isinya lebih dari satu baris. Program berikut menampilkan kedua bentuk tersebut pada iterator each dan map.
# Dua bentuk penulisan block pada iterator
anggota = ["Ali", "Budi", "Citra"]
anggota.each do |nama|
puts "Piket: #{nama}"
end
anggota.each { |nama| puts "Bentuk kurawal: #{nama}" }
puts anggota.map { |nama| nama.length }Piket: Ali
Piket: Budi
Piket: Citra
Bentuk kurawal: Ali
Bentuk kurawal: Budi
Bentuk kurawal: Citra
3
4
5Pemanggilan anggota.each menyerahkan blok yang berisi puts, sehingga badan blok berjalan sekali untuk setiap elemen array. Bentuk kurawal pada pemanggilan kedua melakukan hal yang sama dengan penulisan yang lebih padat. Pada baris terakhir, metode map menjalankan blok { |nama| nama.length } untuk setiap elemen dan mengumpulkan nilai kembaliannya menjadi array baru, yang kemudian dicetak satu angka per baris oleh puts. Pola metode dengan blok seperti inilah yang digunakan sehari-hari pada pengolahan koleksi.
yield menjalankan blok#
Di dalam metode, kata kunci yield menjalankan blok yang menyertai pemanggilan metode tersebut. Posisi yield menentukan titik di mana badan blok berjalan, dan setiap yield menjalankan blok sekali. Metode berikut memanggil yield dua kali, sehingga badan blok juga berjalan dua kali.
def dua_kali
yield
yield
end
dua_kali do
puts "Baris dicatat"
endBaris dicatat
Baris dicatatMetode dua_kali tidak berisi logika apa pun tentang pekerjaan yang dijalankan, sedangkan blok menyediakan baris yang dicetak. Kendali berpindah dari badan metode ke blok setiap kali yield dieksekusi, lalu kembali ke badan metode setelah blok selesai. Diagram berikut merangkum alur tersebut.
Alur dua arah ini berlaku untuk semua metode penerima blok, termasuk each dan times yang memanggil yield dari dalam perulangannya. Blok tidak pernah berjalan dengan sendirinya, melainkan hanya pada titik yield di badan metode yang memanggilnya. Pemahaman alur ini menjadi dasar untuk membaca setiap metode penerima blok.
Nilai kembalian blok#
Eksekusi yield bernilai sesuai nilai kembalian blok, sehingga metode dapat menggunakan hasil pekerjaan blok untuk melanjutkan prosesnya. Nilai kembalian blok adalah nilai ekspresi terakhir di dalam badannya, sebagaimana metode. Contoh berikut menyisipkan yield di dalam interpolasi string, sehingga hasil blok langsung menjadi bagian kalimatnya.
def laporan
"Nilai tertinggi: #{yield}"
end
puts laporan { [78, 90, 85].max }Nilai tertinggi: 90Pada pemanggilan tersebut, interpolasi menjalankan yield, blok menghitung nilai tertinggi dari tiga nilai ujian, dan nilai 90 mengisi kalimat laporan. Metode menyediakan kerangka kalimat, sedangkan blok menyediakan perhitungan. Pola yang sama digunakan metode map, yaitu mengumpulkan nilai kembalian blok dari setiap elemen menjadi array baru, sehingga kebiasaan mengakhiri blok dengan ekspresi yang ingin dikembalikan penting untuk dijaga.
Argumen blok berbentuk |x|#
Nilai yang diserahkan kepada blok diterima melalui daftar parameter yang ditulis di antara dua garis vertikal, misalnya |x|. Metode yang memanggil yield dapat menyertakan nilai, dan setiap nilai mengisi parameter blok menurut urutannya. Pada hash, iterator each menyampaikan kunci dan nilai setiap entri sebagai dua nilai terpisah, sehingga blok menerima dua parameter sekaligus.
rekap = { "Ali" => 78, "Budi" => 65, "Citra" => 90 }
rekap.each do |nama, nilai|
puts "#{nama}: #{nilai}"
endAli: 78
Budi: 65
Citra: 90Parameter nama menerima kunci dan nilai menerima angkanya, dengan tanda koma sebagai pemisah di antara keduanya. Jumlah parameter blok tidak harus persis sama dengan jumlah nilai yang disampaikan metode, karena Ruby mengisi parameter yang tidak mendapat nilai dengan nil dan membuang kelebihan nilai tanpa pesan. Meski begitu, jumlah parameter yang sesuai dengan nilai yang disampaikan tetap menjadi bentuk yang paling jelas untuk dibaca.
Blok melihat variabel sekitarnya#
Blok membaca dan mengubah variabel lokal yang berada di sekitar tempat blok itu ditulis, sifat yang membedakan blok dari badan metode. Badan metode memiliki lingkup variabel lokal sendiri dan tidak melihat variabel di luarnya, sedangkan blok berbagi lingkup dengan kode yang melingkupinya. Sifat ini digunakan untuk menempatkan penghitung di luar perulangan, sementara blok memperbarui nilainya di dalam badan perulangan.
# Menghitung kemunculan kata tertentu dengan block
teks = "block menyelesaikan pekerjaan kecil, dan block tersedia di mana-mana"
jumlah = 0
teks.split.each do |satu|
jumlah += 1 if satu == "block"
end
puts "Kata block muncul #{jumlah} kali"Kata block muncul 2 kaliVariabel jumlah didefinisikan di luar blok, diperbarui di dalam blok, dan nilainya tersisa setelah perulangan berakhir sehingga dapat dicetak. Pembaruan tersebut hanya mungkin karena blok berbagi lingkup dengan kode yang melingkupinya. Sebaliknya, parameter blok seperti satu hanya hidup di dalam blok, sehingga tidak meninggalkan variabel sisa setelah perulangan selesai.
Kesalahan umum#
Kesalahan yang paling sering terjadi pada mekanika blok adalah memanggil metode yang mengandung yield tanpa menyertakan blok. Kasus ini diperagakan dengan berkas yang sengaja mengandung kesalahan, lalu dijalankan dari terminal untuk melihat pesan error aslinya. Penanda # tidak-dijalankan pada baris pertama potongan kode bukan bagian program, melainkan tanda bahwa kode diperagakan lewat berkasnya.
# tidak-dijalankan
def catat(judul)
puts "== #{judul} =="
yield
end
catat("Rekap harian")# menjalankan berkas yang memanggil yield tanpa block
ruby yield-tanpa-block.rbyield-tanpa-block.rb:3:in 'Object#catat': no block given (yield) (LocalJumpError)
from yield-tanpa-block.rb:6:in '<main>'
== Rekap harian ==Pesan no block given (yield) menyatakan bahwa yield menemui pemanggilan tanpa blok, dan kelas errornya adalah LocalJumpError. Baris == Rekap harian == tetap tercetak karena letaknya sebelum yield, sedangkan eksekusi berhenti pada saat yield dijalankan. Perbaikannya adalah menyertakan blok pada setiap pemanggilan metode yang mengandung yield, atau memeriksa block_given? terlebih dahulu apabila pemanggilan tanpa blok memang boleh terjadi.
Ringkasan#
- Blok ditulis di antara
do ... endatau{ }, dan keduanya berperilaku sama pada pemanggilan yang sama. yieldmenjalankan blok pada posisi di manayielditu berada, dan nilai kembalian blok menjadi nilaiyield.- Nilai yang diserahkan kepada blok diterima parameter di antara dua garis vertikal, misalnya
|nama, nilai|. - Blok berbagi lingkup dengan kode di sekitarnya, sedangkan parameternya hanya hidup di dalam blok.
Referensi#
- Metode — Dokumentasi Ruby 3.4 — Bagian Block Argument menjelaskan blok yang menyertai pemanggilan metode dan parameternya.
- Memanggil Metode — Dokumentasi Ruby 3.4 — Bagian Block Argument menjelaskan cara blok diserahkan pada sisi pemanggilan.