Sekilas Ruby
Ruby merupakan bahasa pemrograman yang interpreted, dinamis, dan open source. Ruby berfokus pada kesederhanaan dan produktivitas, sehingga Ruby merupakan sahabat baik programmer. Ruby mensupport multiparadigma: berorientasi objek, imperatif, reflektif, dan fungsional.Pada bagian ini, kamu dapat mencoba-coba kode di bawah dengan mengklik tombol "Jalankan".
puts "Halo Ruby!" # Ini komentar puts 3+6.0 # 9.0 =begin Ini komentar untuk banyak baris =end total_partisipasi = 30 puts total_partisipasi puts "Total orang yang hadir adalah #{total_partisipasi}" def print_halo # ini method tanpa argumen puts "halo" end print_halo # jalankan method print_halo def kali_dua(angka) # ini method dengan argumen puts "#{angka+angka}" end kali_dua(5) kali_dua 5 # boleh tidak pakai kurung puts <<-EOL Bisa print banyak baris lho! EOL
Konstanta dan Variabel
JEDA_TAHUN = 3 # konstanta # JEDA_TAHUN = 10 # error karena sudah diassign $tahun_ini = 2013 # variabel global puts "Sekarang tahun #{$tahun_ini}." umur = 20 # variabel lokal puts "Sekarang umur saya #{umur}. Ngga deng becanda." class Mobil @@sim = "A" # variabel kelas def nama @nama # variabel object end def nama=(nama) @nama = nama end def self.sim # class method @@sim end end puts "Mobil biasanya pakai SIM #{Mobil.sim}." mobilku = Mobil.new mobilku.nama = "Mobil Balap" puts "Mobilku #{mobilku.nama}. Jadi aku pake SIM #{Mobil.sim}."
Tipe dan Struktur Data
Semua tipe data merupakan Object, termasuk tipe data primitif seperti Integer, Float, dan Boolean. Bahkan, nil dan Class pun merupakan Object.umur = 20 # Integer puts umur suhu = 2.98 # Float puts suhu masih_muda = true # Boolean puts masih_muda remaja = umur < 20 && umur > 12 # Boolean puts remaja # puts nama # error karena belum diassign nama = nil # NilClass puts nama
Symbol
Symbol kelihatan hampir seperti String, hanya saja karakter yang diperbolehkan adalah titik dua (:) dan sama seperti variabel. Bedanya, Symbol selalu ada di memory/tidak pernah dihapus dari memory setelah dibuat pertama kali.nama_konfigurasi = :rute # :rute adalah Symbol puts nama_konfigurasi # kalau diprint saja tidak kelihatannya tidak ada bedanya dengan string puts :rata_kanan puts "rata_kanan" puts :"ini_string".inspect puts :RataKiri.inspect puts "RataKiri".inspect puts "nenek moyangku seorang pelaut".to_sym.inspect # :suka%suka # error
Dapat Diiterasi: Array, Hash, Set, dan Range
Array
tinggi_murid = [156, 160, 149] tinggi_murid << 189 # tambahkan 189 ke akhir Array tinggi_murid puts tinggi_murid.inspect nama_singkat = %w{andi budi nani} # Array berisi String nama_singkat = ["andi", "budi", "nani"] # sama dengan di atas # Iterasi nama_singkat.each do |nama| puts "Halo #{nama}!" end; puts nama_singkat.each { |nama| puts "Halo #{nama}!" } puts nama_singkat.each { |nama| puts "Halo #{nama}!" } puts puts nama_singkat.map { |nama| "Halo #{nama}" }.inspect # Iterasi dengan Index nama_singkat.each_with_index do |nama, index| puts "Tinggi #{nama} adalah #{tinggi_murid[index]}" end; puts nama_singkat.each_with_index { |nama, index| puts "Tinggi #{nama} adalah #{tinggi_murid[index]}" } puts nama_singkat.each_with_index { |nama, index| puts "Tinggi #{nama} adalah #{tinggi_murid[index]}" }
Hash
Hash mirip seperti sebuah tabel key-value, dengan key tidak berduplikat.h = { key: "value" } puts h puts key: "value" puts "key" => "value", x: "y" puts :hihi => 8 puts Hash["a", 100, "b", 200] puts Hash[ [ ["a", 100], ["b", 200] ] ] puts Hash["a" => 100, "b" => 200] hash = { hari_ini: 19, "besok" => 10 } puts hash.keys.inspect puts hash.values.inspect puts hash["kemarin"] # nil kalau diprint jadi string kosong puts hash[:hari_ini] puts hash["besok"] # Iterasi hash.each_pair do |key, value| puts "#{key.to_s} jajan #{value} ribu" end hash.merge!(kemarin: 30) puts hash[:kemarin]
Set
Set merupakan koleksi dengan elemen tak berurut tanpa duplikat. Set mirip dengan Array, tetapi kecepatan pencarian elemen mirip dengan Hash.s1 = Set.new [1, 2] s2 = [1, 2].to_set puts s1 == s2 s1.add("foo") puts s1.inspect s1.merge([2, 6]) puts s1.inspect puts s1.subset? s2 puts s2.subset? s1
Range
Range merupakan jajaran dari Object yang memiliki elemen awal dan akhir.range = (1..3) # Termasuk elemen terakhir puts range.to_a.inspect puts (1...3).to_a.inspect # Tidak termasuk elemen terakhir puts (0..-1).to_a.inspect # -1 adalah element ke n-1 puts (-1..-5).to_a.inspect puts (-5..-1).to_a.inspect puts ('a'..'e').to_a.inspect puts ('a'...'e').to_a.inspect puts puts "Berat Badanku..." berat_badanku_tiap_hari = [50, 51, 50, 49, 52] puts berat_badanku_tiap_hari[2..3].inspect puts berat_badanku_tiap_hari[0..-1].inspect puts berat_badanku_tiap_hari[0...-1].inspect puts berat_badanku_tiap_hari[-5...-1].inspect puts berat_badanku_tiap_hari[-1...-5].inspect puts nilai = 10 case nilai when (9..10) puts "Nilaimu A" when (8...9) puts "Nilaimu B" when (7...8) puts "Nilaimu C" else puts "Nilaimu D" end
Konversi Tipe Data
Hampir semua tipe data di atas dapat dikonversi ke tipe data lain. Berikut beberapa contoh cara mengkonversi tipe data.puts 10.to_f # Integer ke Float puts 10.4279.to_s # Float ke String puts [3, 4, 5].to_s # Array ke String puts (1..8).to_a.inspect # Range ke Array puts :hewan.to_s # Symbol ke String puts "hewan".to_sym # String ke Symbol puts nil.to_i # NilClass ke Integer puts({ key: "value" }.to_a.inspect) # Hash ke Array
Operasi Logika dan Aritmatika
Ini sebagai info aja. Tidak harus hafal semua kok.+
tambah-
kurang*
kali/
bagi%
modulus**
pangkat&
dan (untuk bilangan berbasis 2)|
atau (untuk bilangan berbasis 2)^
XOR (untuk bilangan berbasis 2)~
invert bit (untuk bilangan berbasis 2)<<
shift kiri (untuk bilangan berbasis 2)>>
shift kanan (untuk bilangan berbasis 2)&&
dan (untuk Boolean)and
dan (untuk Boolean), tetapi prioritas rendah||
atau (untuk Boolean)or
atau (untuk Boolean), tetapi prioritas rendah!
bukan (untuk Boolean)not
bukan (untuk Boolean)==
sama dengan>
lebih dari<
kurang dari>=
lebih dari atau sama dengan<=
kurang dari atau sama denganputs 3+8 puts 8*9.1 puts 8/4+10 puts 2**3 puts 3 | 6 # 11 (basis 2) atau 100 (basis 2) puts 3 ^ 2 # 11 (basis 2) XOR 10 (basis 2) puts 7 & 2 puts 10 % 5 # habis dibagi 5 puts 10 % 6 # ada sisa puts x = 9 puts x < 1 || x >= 10 puts x == '9' or x == 9 # prioritas or lebih rendah daripada || puts "#{x == '9' or x == 9}" puts x.is_a?(Integer) && x < 29 puts x.is_a?(Integer) and x < 29 puts ([1,2,3] - [1,3]).inspect puts ([1,3,4] + [9,8]).inspect puts ([1,2,3] * 5).inspect puts; puts "Singkat assign variabel dan operasi aritmatika" a = 10 a /= 5 # a = a / 5 puts a a += 19 # a = a + 19 puts a a -= 18 # a = a - 18 puts a a *= 8 # a = a * 8 puts a a %= 2 # a = a % 2 puts a a **= 3 # a = a ** 3 puts a puts; puts "Assign variabel secara paralel" a, b, c = 1, 's', 9 puts "a=#{a} b=#{b} c=#{c}" a, b = b, c puts "a=#{a} b=#{b} c=#{c}"
- Dokumentasi Fixnum
- Techotopia: Ruby Operators
- The Pragmatic Programmer's Guide
- tech addict mark guzman's random musings: ruby gotchas and caveats
Statement Controls
Conditionals
if, else, dan unless# if dan else puts "hore pake if" if true puts "hore pake unless" unless false # Dalam conditional, nil diperlakukan seperti false, dan bukan nil diperlakukan seperti true. puts "hore kebalik pake if" if nil puts "hore kebalik pake unless" unless 7 if true puts "suka kucing" # Ini diprint else puts "suka harimau" end if false puts "suka anjing" else puts "suka kucing" # Ini diprint end # Yang di atas bisa disingkat menggunakan ternary operation true ? puts("hore") : puts("yah kok gitu") # "hore" # Bandingkan yang di atas dengan unless dan else unless true # unless adalah if not puts "suka laba-laba" else puts "suka kucing" # Ini diprint end
# elsif nilai = 10 if nilai >= 9 puts "Nilaimu A" elsif nilai >= 8 # elsif berarti else if puts "Nilaimu B" elsif nilai >= 7 puts "Nilaimu C" else puts "Nilaimu D" end mood = :pengen_gerak if mood == :pengen_belanja puts "Cari baju ah" elsif mood == :pengen_gerak puts "Lari marathon biar seger" elsif mood == :pengen_tidur puts "Hibernasi seharian di rumah" else puts "Main sama kucing aja deh" end
==
mood = :pengen_gerak case mood when :pengen_belanja puts "Cari baju ah" when :pengen_gerak puts "Lari marathon biar seger" when :pengen_tidur puts "Hibernasi seharian di rumah" else puts "Main sama kucing aja deh" end
Loop
tinggi_badan = [170, 150, 160] puts "for" for tinggi in tinggi_badan puts "Tinggi badanmu #{tinggi} cm." end puts; puts "each" # yang di atas sama dengan .each pada Array dan Set tinggi_badan.each { |tinggi| puts "Tinggi badanmu #{tinggi} cm." } # while: jalankan hingga kondisi tidak terpenuhi puts; puts "while" n = 0 while n < tinggi_badan.size puts tinggi_badan[n] n += 1 end # until: jalankan hingga kondisi terpenuhi puts; puts "until" n = 0 until n >= tinggi_badan.size puts tinggi_badan[n] n += 1 end puts; puts "begin-end-while" n = -1 begin n += 1 puts tinggi_badan[n] end while n < tinggi_badan.size puts; puts "begin-end-until" n = -1 begin n += 1 puts tinggi_badan[n] end until n >= tinggi_badan.size puts; puts "loop" n = 0 loop do puts tinggi_badan[n] n += 1 break if n >= tinggi_badan.size end # jalankan x kali puts; puts "10 kali tepuk tangan" people = [] 10.times { print "plok " }
Methods
# tanpa argumen def mood_main_sama_kucing mood = :main_sama_kucing puts "Aku lagi mood #{mood}" end mood_main_sama_kucing # dengan satu argumen def moodku(mood) mood = :main_sama_kucing unless mood puts "Aku lagi mood #{mood}" end moodku nil moodku :pengen_gerak # memberi nilai default pada argumen def moodku(mood=:tidur) mood = :main_sama_kucing unless mood puts "Aku lagi mood #{mood}" end moodku # sama dengan suggest_ngapain(:tidur) karena defaultnya :tidur moodku(:pengen_tidur)
# lebih dari satu parameter def moodku(mood1=nil, mood2) for mood in [mood1, mood2] mood = :main_sama_kucing unless mood puts "Aku lagi mood #{mood}" end end moodku :pengen_gerak, nil moodku :pengen_belanja puts # variabel argument, argument bisa terserah berapa aja def moodku(*moods) for mood in moods mood = :main_sama_kucing unless mood puts "Aku lagi mood #{mood}" end end moodku nil, :pengen_belanja, :pengen_gerak puts
Proc
Proc disebut juga closures dalam ilmu komputer. Menurut saya, tipe data ini sangat spesial karena sifatnya seperti method atau sebuah snippet, tetapi dapat diassign seperti variabel.Sekilas Proc
Kamu sebenarnya sudah melihat Proc pada bab Array. Berikut ini sekilas mengenai Proc yang merupakan block dan lambda.# Sudah pernah lihat? tinggi_badan = [170, 160, 150] tinggi_badan.each { |tinggi| puts "Tinggi badanku #{tinggi}cm." } puts; puts "--- block" blok = proc { |tinggi| puts "Tinggi badanku #{tinggi}cm." } # blok = Proc.new { |tinggi| puts "Tinggi badanku #{tinggi}cm." } # sama dengan di atas puts "block merupakan sebuah instance dari #{blok.class}." puts "Apakah block merupakan lambda? #{blok.lambda? ? "Ya" : "Tidak"}" tinggi_badan.each &blok puts; puts "--- lambda" ld = lambda { |tinggi| puts "Tinggi badanku #{tinggi}cm." } # ld = ->(tinggi) { puts "Tinggi badanku #{tinggi}cm." } # sama dengan di atas puts "lambda merupakan sebuah instance dari #{ld.class}." puts ld.lambda? tinggi_badan.each &ld puts # Membuat method dengan argumen sebuah Proc def kelas_blok(&block) puts block.class puts block.lambda? end puts kelas_blok { |tinggi| puts "Tinggi badanku #{tinggi}cm." } puts kelas_blok &(lambda { |tinggi| puts "Tinggi badanku #{tinggi}cm." }) puts kelas_blok &->(tinggi) { puts "Tinggi badanku #{tinggi}cm." }
Perbedaan block dan lambda
block dan lambda terlihat seperti saudara kembar, walaupun secara syntax memang sudah terlihat berbeda. Pada dasarnya, lambda lebih bersifat seperti method, dan block lebih bersifat seperti snippet. Kamu juga perlu tahu 2 perbedaan besar antara keduanya.- lambda cek jumlah argumen (arity), proc tidak.
def jual_baju(handler) harga, n = 99900, 10 handler.call(harga, n) end jual_baju proc { |harga, n, nama_penjaga_kasir| puts "Saya beli #{n} baju dengan harga Rp #{harga} per baju. Yang jaga kasir: #{nama_penjaga_kasir.inspect}" } # error jual_baju ->(harga, n, nama_penjaga_kasir) { puts "Saya beli #{n} baju dengan harga Rp #{harga} per baju. Yang jaga kasir: #{nama_penjaga_kasir.inspect}" }
- Jika
ada return di dalam lambda, maka return akan terjadi di dalam lambda
itu. Jika return ada di block, maka return akan terjadi di dalam block
itu dan juga method yang memanggilnya.
def proc_return proc { return "proc"}.call return "proc_return selesai" end def lambda_return lambda { return "lambda" }.call return "lambda_return selesai" end puts proc_return puts lambda_return; puts def iterasi_array_dengan_proc [1, 17].each { |tanggal_libur| puts "Tanggal #{tanggal_libur} libur!!" return "Udah ah liburannya" if tanggal_libur == 1 } end def iterasi_array_dengan_lambda [1, 17].each &->(tanggal_libur) { puts "Tanggal #{tanggal_libur} libur!!" return "Udah ah liburannya" if tanggal_libur == 1 } end puts iterasi_array_dengan_lambda.inspect; puts puts iterasi_array_dengan_proc.inspect
Mengenal Kemiripan block dan lambda
Pada umumnya, yang bisa kamu lakukan pada block dapat kamu lakukan juga pada lambda. Berikut ini beberapa contoh di mana cara kerja lambda dan proc sama saja.puts "Method yang memiliki argument sebuah Proc" def punya_proc yield end punya_proc { puts "yield proc" } punya_proc &->{ puts "yield lambda" } def punya_proc(&ada_proc) ada_proc.call end punya_proc { puts "call &proc" } punya_proc &->{ puts "call &lambda" } def punya_proc(ada_proc) ada_proc.call end punya_proc proc { puts "call proc" } punya_proc ->{ puts "call lambda" } puts; puts "Method yang memiliki lebih dari satu Proc" def punya_banyak_proc(proc1, proc2) proc1.call proc2.call end punya_banyak_proc proc { puts "call proc1" }, proc { puts "call proc2" } punya_banyak_proc ->{ puts "call lambda1" }, ->{ puts "call lambda2" } puts; puts "Default nilai parameter untuk argumen Proc" def kasih_default yield yield("hihihi") end kasih_default { |ini="default lho"| puts ini } kasih_default &->(ini="default lho"){ puts ini }
Mari Bermain Bersama Proc!
angka = [1, 2, 3, 4] angka.collect! { |n| n ** 2 } puts angka.inspect; puts puts "Memanggil Proc dengan yield" class Array # Patch Array def comot! self.each_with_index do |n, i| self[i] = yield(n) end end end angka.comot! { |n| n ** 2 } puts angka.inspect; puts puts "Memanggil Proc dengan .call" class Array def comot!(&code) self.each_with_index do |n, i| self[i] = code.call(n) end end end angka.comot! &->(n) { n ** 2 } puts angka.inspect; puts puts "Membuat method dengan callback" def jual_baju(callback) callback[:mulai].call puts "Jualan Baju..." callback[:selesai].call end jual_baju(mulai: lambda { puts "Buka Toko Baju" }, selesai: lambda { puts "Tutup Toko Baju" })
- Understanding Ruby Blocks, Procs and Lambdas
- SKORKS: Ruby Procs And Lambdas (And The Difference Between Them)
- StackOverflow: What's the difference between a proc and a lambda in Ruby?
- Dokumentasi Proc
Class
Ruby biasanya cukup object oriented, walaupun functional dan yang lain juga bisa. Ruby punya garbage collector, jadi tidak perlu atur2 alokasi seperti pada C/C++.Deklarasi, Setter dan Getter
class Baju BAHAN_DEFAULT = "Bulu" # konstanta kelas attr_accessor :merek # buat setter dan getter untuk instance variable @merek attr_reader :tahun_desain # buat getter untuk instance variable @tahun_desain attr_writer :ada_stock # buat setter untuk instance variable @ada_stock def initialize(merek=nil) # method spesial yang dipanggil pada saat class baju diinisialisasi @merek = merek puts "merek: #{merek}" end def ada_stock? # tanda tanya biasanya untuk method yang return Boolean @ada_stock end # membuat getter dan setter sendiri def desainer # getter @desainer ? @desainer : "Belum Tahu" end def desainer=(desainer) # setter @desainer = desainer end def self.nama_item # class method "Baju Bagus" end class << self def nomor_rak # class method juga 48953 end end class Kain # nested class def nama "Katun" end end end baju = Baju.new baju = Baju.new("Batique") puts baju.desainer baju.desainer = "XYZ" puts baju.desainer puts Baju.nama_item puts Baju.nomor_rak puts baju.class.nama_item puts Baju::BAHAN_DEFAULT kain = Baju::Kain.new puts kain.nama
Access Modifiers
Secara default, semua method public dan instance variable protected. Kamu bisa mengubah method menjadiprivate
atau protected
, tetapi kamu tidak bisa mengubah instance variable seperti itu.class Baju attr_accessor :merek, :ukuran attr_reader :tahun_desain def desainer # getter @desainer ? @desainer : "Belum Tahu" end def desainer=(desainer) # setter @desainer = desainer end protected :desainer= # method desainer= menjadi protected private :merek, :tahun_desain # method merek dan tahun desain menjadi private protected # yang di bawah ini menjadi protected attr_accessor :barcode # getter dan setter rating menjadi protected def rating # method ini menjadi protected 5 end private # yang di bawah ini menjadi private def warna @warna end end baju = Baju.new # baju.warna # error karena private # baju.rating # error karena protected # baju.merek # error karena private puts baju.desainer; puts # baju.desainer = "Orang Keren" # error karena protected class KostumBadut < Baju def bagus? puts self.rating # subclass bisa akses yang protected rating >= 3 end def warni @warna = "Pelangi" puts warna.inspect self.warna # tidak bisa karena private end end kostum_badut = KostumBadut.new puts "Kostum badutnya bagus? #{kostum_badut.bagus?}" puts kostum_badut.warni
Inheritance
class Baju def desainer # getter @desainer ? @desainer : "Belum Tahu" end def desainer=(desainer) # setter @desainer = desainer end protected # yang di bawah ini menjadi protected attr_accessor :barcode # getter dan setter rating menjadi protected def rating # method ini menjadi protected 5 end private # yang di bawah ini menjadi private def warna @warna end end class LongSleeve < Baju attr_accessor :panjang_lengan end baju = LongSleeve.new baju.panjang_lengan = 10 puts baju.panjang_lengan baju.desainer = "Siapa ya" puts baju.desainer # puts baju.rating # error # puts baju.warna # error
Callback
# self.inherited class Kendaraan def self.inherited(subclass) puts "Subclass baru: #{subclass}" end end class Mobil < Kendaraan end class Motor < Kendaraan end
Patching
Kamu bisa ubah-ubah kelas yang sudah define. Teknik ini disebut juga monkey patching.# alias class Rubyist def say! puts 'hello' end def say_with_log! puts "Calling method..." puts "hello" puts "...Method called" end alias_method :say_without_log!, :say! alias_method :say!, :say_with_log! end
Module
Module merupakan kumpulan methods dan konstanta. Module mirip class, hanya saja dia bisa di-include atau di-extend ke modul atau kelas lain.module DapatDipanggil def panggilan case @jenis_kelamin when :pria "Mr" when :wanita "Ms" else "" end end end module PakaiSeragam def seragam puts "Seragam kotak-kotak" end end class Pegawai include DapatDipanggil # method di dlm modul DapatDipanggil menjadi instance methods Pegawai extend PakaiSeragam # method di dlm modul PakaiSergam menjadi class methods Pegawai attr_accessor :jenis_kelamin, :nama def nama_lengkap "#{panggilan}. #{nama}" end end Pegawai.seragam pegawai = Pegawai.new pegawai.jenis_kelamin = :wanita pegawai.nama = "Jeni" puts pegawai.nama_lengkap
Callback
# self.included dan self.extended module PakaiSeragam def self.included(a) puts "#{self} included di #{a}" end def self.extended(a) puts "#{self} extended di #{a}" end end class Murid extend PakaiSeragam include PakaiSeragam end
# self.method_removed dan self.method_added module PakaiSeragam def self.method_removed(method_name) puts "Hapus method #{method_name.inspect}" end def self.method_added(method_name) puts "Tambah method #{method_name.inspect}" end def self.some_class_method() end def some_instance_method() end class << self remove_method :some_class_method end remove_method :some_instance_method end
Patching
Seperti Class, kamu bisa monkey patch module yang sudah define.module PakaiSeragam def warna puts "Hijau" end end module PakaiSeragam def motif puts "Kotak-kotak" end end
Exceptions
class MyException < Exception end begin raise MyException.new raise Exception rescue MyException => e1 puts e1.inspect rescue Exception puts "Dapat Exception" else puts "Tidak dapat Exception" ensure puts "Ensure" end
Throw dan Catch
Throw dan Catch pada Ruby bukanlah untuk exceptions. Mereka adalah cara untuk memberhentikan eksekusi program terlebih dahulu ketika program tidak perlu berjalan lagi.catch :stop do puts "Aku mau jalan" throw :stop end def udahan for i in (1..10) print "#{i} " throw :udahan if i == 8 end end catch :udahan do udahan end puts throw :halo
Mengenal Metaprogramming
Metaprogramming adalah membuat program yang dapat membuat code dalam runtime. Metaprogramming mudah dilakukan pada Ruby, sehingga menjadi saat umum dipakai.Eval
Ada 3 macam method untuk meng-evaluate sebuah snippet pada Ruby secara dinamis, yakniKernel#eval
, Object#instance_eval
, dan Module#class_eval
.Kernel#eval
Kamu bisa evaluate Ruby dengan menggunakan Kernel#eval walaupun kamu cuma kasih String. Fitur ini biasanya ada pada bahasa yang tidak perlu dicompile seperti PHP.Object#instance_eval
Dengan instance_eval, kamu bisa menambah method atau variabel instance sendiri. Ini sangat mirip dengan patching, tetapi instance_eval cukup umum digunakan untuk membuat Domain-Specific Language (DSL).class Baju def nama(nama) @nama = nama end def deskripsi "Nama baju ini adalah #{@nama}" end def self.buat(&blok) baju = Baju.new baju.instance_eval &blok # Untuk membuat Domain-Specific Language (DSL) baju end end Baju.instance_eval do def nomor_rak puts "Baju adalah instance dari Class, karena itu di sini kita menambah method class" 10 end end puts Baju.nomor_rak puts <<-EOL Kamu bisa buat DSL sendiri hanya dengan instance_eval. Cukup panggil instance_eval pada sebuah object yang sudah diinisialisasi, dan kamu dapat akses ke method instance pada object itu. === EOL baju = Baju.buat do puts "Kamu bisa mengakses method dan variabel instance di sini.\n---" nama "Kostum Badut" end puts baju.deskripsi
Module#class_eval
class_eval
hampir sama dengan instance_eval
, hanya saja class_eval
hanya dapat digunakan pada class atau module saja. Dengan class_eval
kamu bisa menambah method atau variabel instance. Ini juga sangat mirip dengan patching.class Baju def nama(nama) @nama = nama end def deskripsi "Nama baju ini adalah #{@nama}" end end Baju.class_eval do attr_accessor :ukuran def gambaran puts "#{self.deskripsi}. Ukurannya #{ukuran}" end end baju = Baju.new baju.nama "Kostum Badut" baju.ukuran = "XL" baju.gambaran; puts baju.class_eval do def ups_gagal puts "Jadi error deh" end end
Variabel Instance
Kamu dapat dengan mudah mengakses, mengubah, atau mendefine variabel instance secara dinamis.class Baju end puts Baju.instance_variables.inspect Baju.instance_variable_set(:@kode, "BJ") puts Baju.instance_variable_get(:@kode) puts Baju.instance_variables.inspect puts "---" baju = Baju.new puts baju.instance_variables.inspect baju.instance_variable_set(:@nama, "Kostum Badut") puts baju.instance_variable_get(:@nama) puts baju.instance_variables.inspect
Variabel Class
Kamu dapat dengan mudah mengakses, mengubah, atau mendefine variabel class secara dinamis.class Baju end puts; puts "Ubah variabel class" puts Baju.class_variables.inspect Baju.class_variable_set(:@@kode, "BJ") puts Baju.class_variable_get(:@@kode) puts Baju.class_variables.inspect baju = Baju.new puts baju.class_variables # error
Konstanta
Kamu juga bisa dengan mudah mengakses, mengubah, atau mendefine konstanta secara dinamis.class Baju end Baju.const_set(:WARNA_DEFAULT, "Hitam") puts Baju.const_get(:WARNA_DEFAULT) puts Baju.constants.inspect puts Baju.new.constants.inspect # error
Method
Kamu juga dapat dengan mudah mengakses, mengubah, atau mendefine method secara dinamis.class Baju def warna @warna || "Hitam" end define_method(:beli) do puts "Beli baju" end private def kain "Katun" end end Baju.class_eval do define_method(:jual) do |harga| puts "Jual baju dengan harga Rp #{harga}" end define_method(:warna=) do |warna="Hitam"| puts "Warna baju #{warna.inspect}" @warna = warna end end baju = Baju.new # puts baju.kain # tidak bisa panggil method yang private puts baju.send(:kain) baju.warna = # default warna hitam puts baju.warna.inspect baju.warna = "Putih" puts baju.warna.inspect baju.jual 399900 Baju.class_eval do remove_method(:warna) undef_method(:beli) end # baju.warna # error # puts baju.beli # error class Baju def method_missing(*args) puts "Oalah methodnya ngga ada: #{args.inspect}" end end puts; puts "Panggil method yang ga ada" puts baju.ngasal
Sumber-sumber:
- Ruby Metaprogramming
- Metaprogramming Ruby: class_eval and instance_eval
- musings on intarwebz: Simple Academia DSL in Ruby Tutorial
- Ruby Metaprogramming
- yonkeltron.com: Creating a Ruby DSL
- The Ruby Ahead: undef_method != remove_method
Tidak ada komentar:
Posting Komentar