Belajar Ruby - Metaprogramming & Internals
Series/Belajar Ruby/Episode 19
Episode 19 of 23

Belajar Ruby - Metaprogramming & Internals

Episode ini membahas metaprogramming Ruby: send, define_method, method_missing dan respond_to_missing?, instance_eval serta class_eval untuk membangun DSL, lalu internals seperti singleton class, method lookup chain, dan hooks untuk plugin architecture.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sebagian besar kekuatan Ruby berasal dari dinamismenya: program bisa menulis program. Metaprogramming adalah teknik membuat method, mengubah objek, dan mendefinisikan perilaku saat runtime. Episode 19 menjelaskan teknik-teknik ini dan internals yang mendasarinya.

Setelah episode 18, kalian bisa mengetik. Sekarang kita belajar fleksibilitas yang membuat framework seperti Rails dan Sinatra begitu ekspresif — dari send dan define_method hingga DSL yang memetakan konfigurasi jadi kode.

Teknik Metaprogramming Dasar

send dan define_method

send memanggil method secara dinamis — nama method bisa berupa string atau simbol yang baru diketahui saat runtime. define_method membuat method baru pada kelas:

Rubysend dan define_method
class Klien
  def panggil(nama, *args)
    send(nama, *args)
  end
 
  def self.buat_getter(attr)
    define_method(attr) { instance_variable_get("@#{attr}") }
  end
end

send(nama, *args) memanggil method bernama nama dengan argumen apa pun. define_method(attr) membuat getter otomatis untuk setiap atribut — pola yang dipakai untuk menghindari kode berulang. Hati-hati: jangan memanggil send dengan nama method dari input pengguna tanpa whitelist.

method_missing dan respond_to_missing?

Saat method tidak ditemukan, Ruby memanggil method_missing. Ini dasar dari banyak DSL — objek bisa menangkap panggilan yang tidak dikenal:

Rubymethod_missing untuk DSL
class Pengaturan
  def method_missing(nama, *args)
    if nama.to_s.end_with?("=")
      instance_variable_set("@#{nama.to_s.chop}", args.first)
    else
      super
    end
  end
 
  def respond_to_missing?(nama, include_private = false)
    nama.to_s.end_with?("=") || super
  end
end

def method_missing(nama, *args) menangkap pemanggilan seperti pengaturan.port = 3000. respond_to_missing? wajib di-override agar respond_to? juga mengakui method dinamis ini — tanpa itu, protocol objek seperti serialisasi bisa salah.

instance_eval dan class_eval untuk DSL

instance_eval mengevaluasi block dengan self objek itu sendiri, sehingga method dan variabel instance terbuka langsung. Inilah cara framework membuat konfigurasi seperti config.port = 3000 terasa seperti DSL:

RubyDSL dengan instance_eval
class Server
  def initialize(&block)
    instance_eval(&block)
  end
 
  def port(value)
    @port = value
  end
 
  def workers(value)
    @workers = value
  end
end
 
server = Server.new do
  port 3000
  workers 4
end

Server.new do ... end mengeksekusi block dalam konteks instance, sehingga port 3000 menjadi pemanggilan method, bukan assignment. class_eval bekerja serupa untuk level kelas. DSL seperti ini membuat API kalian ekspresif dan dekat dengan bahasa manusia.

Internals: Singleton Class dan Method Lookup

Singleton Class

Setiap objek Ruby memiliki singleton class — kelas tak terlihat yang menyimpan method khusus objek tersebut. Method yang didefinisikan dengan def self. atau def obj.method tinggal di sini:

RubySingleton method dan singleton class
server = Server.new { port 8080 }
def server.ping
  "pong"
end
 
puts server.singleton_class.ancestors.first

def server.ping menambahkan method hanya ke satu objek. server.singleton_class mengakses kelas tersembunyi tersebut. Pahami singleton class karena ia ikut menentukan cara Ruby mencari method.

Method Lookup Chain

Ketika kalian memanggil method, Ruby menelusuri rantai: singleton class objek, lalu kelasnya, modul yang di-include, kelas induk, dan seterusnya hingga BasicObject. Urutan inilah yang menentukan method mana yang menang:

RubyUrutan lookup method
puts Server.ancestors
puts server.singleton_class.ancestors

Server.ancestors mencetak rantai kelas dan modul dari atas ke bawah. prepend memasukkan modul di posisi terdepan sehingga method-nya menang atas kelas. Memahami urutan ini adalah kunci memprediksi perilaku di kode yang banyak memakai mixin.

Hooks dan Plugin Architecture

Hooks adalah method yang dipanggil Ruby saat kejadian tertentu terjadi — misalnya ketika modul di-include (included) atau ketika method baru ditambahkan (method_added). Kombinasi hooks dan metaprogramming membangun plugin architecture:

RubyHook included untuk plugin
module Audit
  def self.included(base)
    base.extend(ClassMethods)
    puts "#{base} memakai plugin Audit"
  end
 
  module ClassMethods
    def catat_aksi
      puts "aksi dicatat"
    end
  end
end
 
class Transaksi
  include Audit
end

module Audit dipanggil included ketika dimasukkan ke kelas; base.extend(ClassMethods) membuat method modul menjadi class method. Plugin yang ditulis dengan pola ini bisa menambahkan perilaku, memvalidasi, atau mencatat aktivitas tanpa mengubah kelas target secara manual.

Warning

Metaprogramming adalah pisau bermata dua. Gunakan untuk membangun API yang ekspresif, tetapi jaga agar kode tetap mudah dibaca dan di-debug. Lebih sedikit keajaiban lebih baik, kecuali keajaiban itu benar-benar menyederhanakan pemakaian.

Penutup

Inti yang harus dibawa pulang:

  • send memanggil method dengan nama dinamis saat runtime.
  • define_method menciptakan method baru secara programatik.
  • method_missing menangkap panggilan yang tidak dikenal dan wajib berpasangan dengan respond_to_missing?.
  • instance_eval membangun DSL dengan mengeksekusi block dalam konteks objek.
  • Singleton class menyimpan method khusus satu objek dan berada di urutan pertama lookup.
  • Server.ancestors menunjukkan urutan method lookup yang menentukan pemenang.
  • Hooks seperti included dan method_added menjadi fondasi plugin architecture.

Di episode 20 kita menjaga kualitas: testing dengan Minitest dan RSpec lengkap dengan mocks, stubs, dan fixtures, alur kerja TDD, lalu RuboCop untuk gaya kode dan SimpleCov untuk coverage. Setelah bisa menulis kode ajaib, kita belajar menuliskannya dengan disiplin.

Belajar Ruby - Metaprogramming & Internals | Belajar Ruby