Modul sebagai namespace

Mendefinisikan module sebagai namespace dan konstanta bersarang di dalamnya.

Daftar isi

Kata kunci module di Ruby memiliki dua peran besar, dan peran pertamanya adalah sebagai wadah nama. Topik ini membahas module sebagai namespace, yaitu ruang nama yang mengelompokkan konstanta di bawah satu nama, mulai dari pendefinisian dan pengaksesan dengan tanda ::, konstanta bersarang, pencegahan tabrakan nama, hingga perbedaan modul dari kelas. Setelah membacanya, konstanta program dapat ditata dalam hierarki yang rapi, dan risiko dua nama yang sama saling menimpa dapat dihindari.

Kata kunci module sebagai wadah nama#

Kata kunci module mendefinisikan sebuah modul, yaitu objek bertipe Module yang dapat menampung konstanta dan metode di bawah satu nama. Ketika program membesar, konstanta yang diletakkan bebas di tingkat atas mudah saling bercampur, sedangkan modul memberi setiap kelompok nilai sebuah alamat tersendiri. Modul sering dipilih sebagai wadah nilai-nilai yang melekat pada satu ranah, misalnya batas pembacaan sensor atau satuan pengukurannya.

Program berikut mendefinisikan modul Sensor yang menampung tiga konstanta, lalu membacanya kembali dengan tanda ::.

ruby sensor.rb
# Modul Sensor menjadi wadah konstanta milik stasiun cuaca.
module Sensor
  BATAS_ATAS = 100
  BATAS_BAWAH = -20
  SATUAN = "derajat Celsius"
end

puts Sensor::BATAS_ATAS
puts Sensor::BATAS_BAWAH
puts Sensor::SATUAN
p Sensor.constants.sort
text Keluaran
100
-20
derajat Celsius
[:BATAS_ATAS, :BATAS_BAWAH, :SATUAN]

Tanda titik dua ganda :: mengakses isi modul dari luar, sehingga Sensor::BATAS_ATAS dibaca sebagai konstanta BATAS_ATAS yang berada di dalam modul Sensor. Metode constants milik modul mendaftar seluruh konstanta yang dimiliki modul secara langsung, dan keluarannya menunjukkan ketiga nama itu tersimpan dalam satu wadah. Tanpa modul, ketiga nama tersebut berada di tingkat atas program dan wilayah kepemilikannya tidak terlihat dari namanya.

Modul juga boleh menampung metode, tetapi untuk peran namespace, isinya yang paling khas adalah konstanta dan modul bersarang. Konstanta yang dimasukkan sebaiknya benar-benar konstan selama program berjalan, misalnya batas alat ukur, faktor konversi, atau nama satuan, karena perubahan nilainya memicu peringatan, sebagaimana dijelaskan pada bagian Mencegah tabrakan nama. Dengan kebiasaan tersebut, kehadiran sebuah modul pada kode lain menjadi petunjuk bahwa di dalamnya terdapat kumpulan nilai yang saling berkaitan dan bermakna pada satu ranah.

Konstanta bersarang dan tanda ::#

Modul dapat didefinisikan di dalam modul lain, dan konstanta yang dihasilkan tersusun dalam hierarki sebagaimana direktori di dalam direktori. Nama modul yang berada di dalam badan modul lain juga merupakan konstanta, karena namanya diawali huruf kapital dan nilainya adalah objek Module. Sifat inilah yang membuat pembacaan Sensor::Kalibrasi::FAKTOR dapat dilakukan dari kiri ke kanan, yaitu turun satu tingkat pada setiap tanda ::.

ruby bersarang.rb
# Modul dapat bersarang, sehingga konstanta tersusun dalam hierarki.
module Sensor
  module Kalibrasi
    FAKTOR = 1.05

    module Rentang
      MINIMUM = 0
      MAKSIMUM = 50
    end
  end
end

puts Sensor::Kalibrasi::FAKTOR
puts Sensor::Kalibrasi::Rentang::MAKSIMUM
p Sensor::Kalibrasi.constants.sort
text Keluaran
1.05
50
[:FAKTOR, :Rentang]

Baris terakhir keluaran memperlihatkan isi modul Sensor::Kalibrasi, yaitu konstanta FAKTOR dan modul bersarang bernama Rentang, dan keduanya terdaftar sebagai anggota tingkat pertama Kalibrasi. Diagram berikut merangkum hierarki yang terbentuk dari kedua contoh program, beserta tiga konstanta lain pada tingkat terluar.

module SensorBATAS_ATASBATAS_BAWAHSATUANmodule KalibrasiFAKTORmodule RentangMINIMUMMAKSIMUMTanda :: menyusuri hierarki dari kotak terluar ke kotak terdalam.
Hierarki konstanta di dalam modul Sensor

Mencegah tabrakan nama#

Namespace terutama digunakan agar dua nama yang sama tidak saling menimpa. Dua bagian program dapat memiliki konstanta bernama sama, misalnya BATAS, dengan maksud yang berbeda. Apabila keduanya diletakkan di tingkat atas, penugasan kedua menimpa nilai pertama dan memunculkan peringatan interpreter. Membungkus setiap nilai dalam modulnya masing-masing membuat kedua konstanta dapat berdampingan tanpa saling mengganggu.

ruby tabrakan.rb
# Dua modul boleh memakai nama konstanta yang sama tanpa saling menimpa.
module SensorSuhu
  BATAS = 100
end

module SensorKelembapan
  BATAS = 80
end

puts SensorSuhu::BATAS
puts SensorKelembapan::BATAS

begin
  puts BATAS
rescue NameError => e
  puts e.class
  puts e.message
end
text Keluaran
100
80
NameError
uninitialized constant BATAS

Dua konstanta BATAS kini memiliki alamat penuh yang berbeda, yaitu SensorSuhu::BATAS bernilai 100 dan SensorKelembapan::BATAS bernilai 80. Baris terakhir program sengaja mencoba membaca nama BATAS langsung dari tingkat atas, dan Ruby menjawab dengan NameError karena nama itu memang tidak terdaftar pada tingkat atas. Kesalahan semacam ini lazim muncul ketika konstanta dipindahkan ke dalam modul, sedangkan baris lain masih membacanya dengan alamat lama, sehingga pesan errornya justru menunjukkan letak baris yang perlu diperbarui.

Module bukan kelas#

Modul menyerupai kelas karena keduanya menampung nama dan metode, tetapi modul tidak dapat diinstansiasi. Tidak ada objek baru yang dibuat dari sebuah modul, karena modul tidak menyediakan metode new. Program berikut memanggil new pada modul Sensor dan menangkap errornya untuk membuktikan perilaku itu.

ruby bukan-kelas.rb
# Modul tidak bisa diinstansiasi karena tidak menyediakan metode new.
module Sensor
  BATAS = 100
end

begin
  Sensor.new
rescue NoMethodError => e
  puts e.class
  puts e.message
end

puts Sensor.class
p Class.superclass
text Keluaran
NoMethodError
undefined method 'new' for module Sensor
Module
Module

Pesan error menyatakan penyebabnya secara langsung, yaitu metode new memang tidak dimiliki modul. Dua baris terakhir melengkapi gambaran tersebut, yaitu Sensor.class mengembalikan Module dan Class.superclass juga mengembalikan Module, sehingga kelas pada dasarnya adalah modul yang ditambah kemampuan membuat instans. Konsisten dengan sifat itu, Ruby juga menolak sebuah modul dijadikan kelas induk pada pewarisan, karena rantai pewarisan memang harus berupa kelas. Pemilihan antara keduanya dapat didasarkan pada pertanyaan sederhana, yaitu apakah kelompok nilai itu perlu dibuat sebagai objek. Apabila tidak, modul adalah wadah yang tepat, sedangkan kemampuannya menampung metode menjadi dasar penggunaan modul sebagai mixin, yaitu mekanisme berbagi metode antarkelas.

Ringkasan#

  • Kata kunci module mendefinisikan objek Module yang menampung konstanta di bawah satu nama, dan tanda :: mengakses isinya.
  • Modul dapat bersarang sehingga alamat konstanta bertingkat, misalnya Sensor::Kalibrasi::FAKTOR, dan nama modul bersarang juga berupa konstanta.
  • Dua modul boleh menggunakan nama konstanta yang sama tanpa saling menimpa, sedangkan pembacaan dengan alamat yang salah memunculkan NameError.
  • Modul tidak dapat diinstansiasi karena tidak memiliki metode new, dan Class.superclass mengembalikan Module.

Referensi#

  • Module — Ruby — Dokumentasi kelas Module, termasuk metode constants dan peran modul sebagai wadah nama.
  • Assignment — Ruby — Bagian local variables dan constants menjelaskan penamaan serta lingkup konstanta.