1. Pengenalan Ruby
Ruby adalah bahasa pemrograman tingkat tinggi yang dibuat oleh Yukihiro Matsumoto (biasa dipanggil "Matz") dan pertama kali dirilis pada tahun 1995. Ruby dirancang dengan filosofi bahwa pemrograman harus menyenangkan dan produktif β Matz ingin menciptakan bahasa yang tidak hanya fungsional tetapi juga membahagiakan untuk digunakan.
Ruby dikenal dengan sintaksnya yang elegan dan intuitif, menjadikannya salah satu bahasa yang paling mudah dipelajari. Ruby digunakan secara luas untuk pengembangan web (terutama dengan framework Ruby on Rails), scripting, otomasi, dan berbagai aplikasi backend. Matz menginspirasi banyak bahasa modern seperti Python, JavaScript, dan Go.
Mengapa Memilih Ruby?
| Keunggulan | Penjelasan |
|---|---|
| Sintaks Elegan | Ruby dirancang agar terbaca seperti bahasa Inggris, sangat natural dan menyenangkan |
| Object-Oriented Sepenuhnya | Semua data di Ruby adalah objek, termasuk angka dan string |
| Block & Iterator | Fitur powerful untuk menulis kode yang ringkas dan ekspresif |
| Ruby on Rails | Framework web terkenal yang memungkinkan pembuatan aplikasi web dengan cepat |
| Gems (Package) | Ekosistem ribuan library yang siap digunakan melalui RubyGems |
| Open Source & Gratis | Dilisensikan di bawah Ruby License, bebas digunakan untuk tujuan apapun |
Ruby vs Bahasa Lain
| Aspek | Ruby | Python | JavaScript |
|---|---|---|---|
| Tipe | Interpreted | Interpreted | Interpreted (JIT) |
| Paradigma | OO Sepenuhnya | Multi-paradigma | Multi-paradigma |
| Sintaks | π’ Elegan & Ekspresif | π’ Sederhana | π‘ Sedang |
| Web Framework | Rails (sangat produktif) | Django, Flask | Express, Next.js |
| Cocok untuk | Web Dev, Startup, Scripting | AI, Data Science | Frontend & Fullstack |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β EKOSISTEM RUBY β β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β β Web Dev β β CLI Toolsβ β Testing & β β β β Rails β β Thor β β Development β β β β Sinatra β β GLI β β RSpec, Minitest β β β β Hanami β β Rake β β RuboCop β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β β Data β β DevOps β β Gems & β β β β Processingβ β Capistranoβ β Libraries β β β β ActiveRecordβ Ansible β β RubyGems.org β β β β Sequel β β Chef β β Bundler β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Instalasi Ruby
Ruby bisa diinstal di semua sistem operasi utama. Cara yang direkomendasikan adalah menggunakan version manager seperti Rbenv atau rbenv untuk mengelola beberapa versi Ruby.
Instalasi di Windows
# 1. Kunjungi https://rubyinstaller.org/ # 2. Download Ruby+Devkit versi terbaru (Ruby 3.3+) # 3. Jalankan installer # 4. Setelah instalasi, jalankan ridk install untuk menginstal devkit # Verifikasi instalasi di Command Prompt / PowerShell: ruby --version # Output: ruby 3.3.3 (2024-06-12 revision e12f4fa7f9) [x64-mingw-ucrt] gem --version # Output: 3.5.14 # Instal bundler untuk dependency management: gem install bundler
Instalasi di macOS
# Menggunakan Homebrew: brew install rbenv ruby-build # Setup rbenv di shell (~/.zshrc atau ~/.bash_profile): echo 'eval "$(rbenv init - zsh)"' >> ~/.zshrc source ~/.zshrc # Instal Ruby versi terbaru: rbenv install 3.3.3 rbenv global 3.3.3 # Verifikasi: ruby --version # Output: ruby 3.3.3 (2024-06-12 revision e12f4fa7f9) # Ruby sudah terpasang di macOS secara default (Ruby 2.x), # tapi disarankan menggunakan rbenv untuk versi terbaru
Instalasi di Linux (Ubuntu/Debian)
# Install dependencies terlebih dahulu sudo apt update && sudo apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev # Menggunakan rbenv (recommended): curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash echo 'eval "$(rbenv init - bash)"' >> ~/.bashrc source ~/.bashrc # Instal Ruby: rbenv install 3.3.3 rbenv global 3.3.3 # Atau gunakan apt (lebih cepat tapi versi mungkin lebih lama): # sudo apt install ruby-full # Verifikasi: ruby --version gem --version
Program Ruby Pertama
# File: hello.rb puts "Halo, dunia!" puts "Selamat datang di Ruby!" puts "Nama saya: BeebaneLabs" # Menjalankan dari terminal: # ruby hello.rb # # Output: # Halo, dunia! # Selamat datang di Ruby! # Nama saya: BeebaneLabs
Ruby Interactive Console (IRB)
# Buka terminal, ketik "irb" atau "ruby" untuk masuk console interaktif # irb(main):001:0> puts "Hello!" # Hello! # => nil # irb(main):002:0> 2 + 3 # => 5 # irb(main):003:0> "Ruby" * 3 # => "RubyRubyRuby" # irb(main):004:0> exit # Keluar dari IRB
Gunakan rbenv atau rvm sebagai version manager untuk mengelola beberapa versi Ruby di satu komputer. Sangat berguna saat bekerja di proyek yang membutuhkan versi Ruby berbeda. Jangan lupa instal Bundler (gem install bundler) untuk mengelola dependency Ruby.
3. Variabel dan Tipe Data
Variabel di Ruby digunakan untuk menyimpan data. Ruby menggunakan dynamic typing, sehingga Anda tidak perlu mendeklarasikan tipe data secara eksplisit. Ruby memiliki konvensi penamaan yang unik berdasarkan scope variabel.
Jenis Scope Variabel di Ruby
| Jenis | Penanda | Scope | Contoh |
|---|---|---|---|
| Local Variable | Tanpa penanda | Method/block yang mendeklarasikannya | nama = "Budi" |
| Instance Variable | @ | Instance dari class | @umur = 25 |
| Class Variable | @@ | Semua instance class | @@jumlah = 0 |
| Global Variable | $ | Seluruh program | $app_name = "MyApp" |
| Constant | Huruf besar awal | Konstan, tidak boleh diubah | PI = 3.14159 |
Mendeklarasikan Variabel
# Local variables β tanpa penanda apapun
nama = "Budi Santoso" # string
umur = 25 # integer
tinggi = 175.5 # float
is_active = true # boolean
# Menampilkan nilai variabel
puts nama # Budi Santoso
puts "Umur: #{umur} tahun" # Umur: 25 tahun (string interpolation)
# Ruby mendeteksi tipe secara otomatis
x = 10 # x adalah Integer
x = "sekarang string" # x sekarang String β tidak masalah!
# Constant β dimulai dengan huruf besar
PI = 3.14159
MAX_SIZE = 100
puts PI # 3.14159
# PI = 3.0 # Warning: PIε·²θ’«θ΅εΌ
# Aturan penamaan:
# β
nama_lengkap, umur_pengguna, _private_var, var_name2
# β 2angka, nama-lengkap, my var (ada spasi)
# β οΈ Nama class harus huruf besar: MyClass
Tipe Data Dasar
| Tipe | Contoh | Penjelasan |
|---|---|---|
Integer | 42, -10, 0 | Bilangan bulat |
Float | 3.14, -0.5, 2.0 | Bilangan desimal |
String | "hello", 'world' | String / teks |
Symbol | :nama, :status | Simbol unik, efisien untuk identifier |
Boolean | true, false | Nilai benar atau salah |
nil | nil | Tipe kosong (null) |
Array | [1, 2, 3] | Kumpulan data terurut |
Hash | {a: 1, b: 2} | Key-value pairs |
Range | 1..10, 'a'..'z' | Serangkaian nilai |
Konversi Tipe Data
# Konversi tipe data angka_str = "42" angka_int = angka_str.to_i # String β Integer: 42 angka_float = angka_str.to_f # String β Float: 42.0 # Integer β String umur = 25 umur_str = umur.to_s # "25" # Float β Integer pi = 3.14159 pi_int = pi.to_i # 3 # Ke Symbol status = :active # Symbol # Cek tipe data dengan .class puts 42.class # Integer puts "hello".class # String puts 3.14.class # Float puts true.class # TrueClass puts nil.class # NilClass puts :test.class # Symbol puts [1,2,3].class # Array # Cek dengan .is_a? puts 42.is_a?(Integer) # true puts "hi".is_a?(String) # true # Input dari pengguna print "Masukkan nama: " nama = gets.chomp # .chomp menghapus newline print "Masukkan umur: " umur = gets.chomp.to_i # Konversi ke integer
4. Operator
Ruby menyediakan berbagai jenis operator untuk melakukan operasi terhadap data.
Operator Aritmatika
# Operator aritmatika dasar a, b = 15, 4 puts a + b # 19 (penjumlahan) puts a - b # 11 (pengurangan) puts a * b # 60 (perkalian) puts a / b # 3 (pembagian bulat jika kedua integer) puts a.to_f / b # 3.75 (pembagian desimal) puts a % b # 3 (modulus/sisa bagi) puts a ** b # 50625 (pangkat: 15^4) # Shortcut assignment x = 10 x += 5 # x = x + 5 β 15 x -= 3 # x = x - 3 β 12 x *= 2 # x = x * 2 β 24 x /= 4 # x = x / 4 β 6 # Integer division vs Float division puts 7 / 2 # 3 (integer division) puts 7.0 / 2 # 3.5 (float division) puts 7.to_f / 2 # 3.5
Operator Perbandingan dan Logika
# Operator perbandingan β menghasilkan true/false
x, y = 10, 20
puts x == y # false (sama dengan)
puts x != y # true (tidak sama)
puts x > y # false (lebih besar)
puts x < y # true (lebih kecil)
puts x >= 10 # true (lebih besar atau sama)
puts x <= 5 # false (lebih kecil atau sama)
# Operator spaceship (<=>) β unik di Ruby
# Mengembalikan -1, 0, atau 1
puts 5 <=> 3 # 1 (5 lebih besar)
puts 3 <=> 3 # 0 (sama)
puts 2 <=> 5 # -1 (2 lebih kecil)
# Operator logika
umur = 25
punya_sim = true
# AND β kedua kondisi harus true
bisa_mengemudi = umur >= 17 && punya_sim
puts bisa_mengemudi # true
# OR β salah satu kondisi harus true
puts umur < 18 || punya_sim # true
# NOT β membalik nilai boolean
puts !punya_sim # false
# Operator keanggotaan
buah = ["apel", "mangga", "jeruk"]
puts buah.include?("apel") # true
puts buah.include?("pisang") # false
5. Kontrol Alur
Kontrol alur memungkinkan Anda mengatur bagaimana program dieksekusi berdasarkan kondisi tertentu.
If/Unless
# if / elsif / else umur = 20 if umur >= 21 puts "Anda dewasa penuh" elsif umur >= 17 puts "Anda remaja hampir dewasa" elsif umur >= 13 puts "Anda remaja" else puts "Anda masih anak-anak" end # Output: Anda remaja hampir dewasa # One-line if (modifier) puts "Halo!" if umur >= 18 # Output: Halo! # unless (kebalikan dari if) unless umur < 18 puts "Anda boleh masuk" end # unless modifier puts "Selamat datang" unless umur < 18
Case Statement
# case / when β seperti switch case yang powerful
hari = "Senin"
case hari
when "Senin"
puts "Hari Senin β semangat!"
when "Selasa", "Rabu", "Kamis"
puts "Hari kerja biasa"
when "Jumat"
puts "Jumat β hari yang menyenangkan!"
when "Sabtu", "Minggu"
puts "Weekend β waktunya libur!"
else
puts "Hari tidak valid"
end
# case dengan range dan regex
suhu = 35
status = case suhu
when 0..15 then "Dingin π₯Ά"
when 16..25 then "Sejuk π"
when 26..35 then "Panas π₯΅"
else "Ekstrem π₯"
end
puts status # Panas π₯΅
# case tanpa argument (pattern matching style)
input = "abc123"
case input
when /^\d+$/ then "Angka saja"
when /^[a-z]+$/ then "Huruf saja"
when /^\w+$/ then "Alphanumeric"
else "Campuran"
end
Looping
# while loop
i = 1
while i <= 5
puts "Iterasi ke-#{i}"
i += 1
end
# until loop (kebalikan while)
i = 1
until i > 5
puts "Iterasi ke-#{i}"
i += 1
end
# for loop
for i in 1..5
puts "Angka: #{i}"
end
# times loop
5.times do |i|
puts "times ke-#{i}"
end
# upto / downto
1.upto(3) do |i|
puts "Up: #{i}"
end
5.downto(1) do |i|
puts "Down: #{i}"
end
# each pada Range
(1..5).each { |i| puts i }
# break dan next
3.times do |i|
break if i == 2 # keluar dari loop
puts "i=#{i}"
end
3.times do |i|
next if i == 1 # skip iterasi ini
puts "i=#{i}"
end
# loop dengan break (do-while style)
counter = 0
loop do
counter += 1
puts "Counter: #{counter}"
break if counter >= 5
end
6. Method dan Fungsi
Method di Ruby didefinisikan dengan kata kunci def. Method bisa menerima parameter, mengembalikan nilai, dan bahkan menggunakan parameter default.
Method Dasar
# Method sederhana
def sapa
puts "Halo, selamat datang!"
end
sapa # Memanggil method
sapa() # Juga valid
# Method dengan parameter
def sapa nama
puts "Halo, #{nama}!"
end
sapa "Budi" # Halo, Budi!
sapa("Rina") # Halo, Rina!
# Method dengan multiple parameter
def tambah a, b
return a + b # return bisa ditulis atau tidak
end
hasil = tambah(5, 3)
puts hasil # 8
# Nilai kembalian β Ruby otomatis mengembalikan ekspresi terakhir
def kali a, b
a * b # Tidak perlu kata kunci return!
end
puts kali(4, 3) # 12
# Parameter default
def sapa_lengkap nama, greeting = "Halo"
puts "#{greeting}, #{nama}!"
end
sapa_lengkap "Budi" # Halo, Budi!
sapa_lengkap "Budi", "Selamat pagi" # Selamat pagi, Budi!
# Keyword arguments
def buat_user(nama:, umur:, email:)
puts "User: #{nama}, Umur: #{umur}, Email: #{email}"
end
buat_user(nama: "Budi", umur: 25, email: "budi@email.com")
# Variable-length arguments (* splat)
def hitung_total(*angka)
angka.sum
end
puts hitung_total(1, 2, 3, 4, 5) # 15
# Method dengan block
def proses_data(data)
data.each do |item|
yield(item) # yield memanggil block yang diberikan
end
end
proses_data([1, 2, 3]) do |item|
puts "Memproses: #{item * 2}"
end
Accessor Methods
# Membuat getter dan setter manual
class Person
def initialize(nama)
@nama = nama
end
# Getter
def nama
@nama
end
# Setter
def nama=(value)
@nama = value
end
end
p = Person.new("Budi")
puts p.nama # Budi
p.nama = "Rina" # Setter
puts p.nama # Rina
# Menggunakan attr_accessor, attr_reader, attr_writer
class Student
attr_accessor :nama, :umur # getter + setter
attr_reader :id # getter saja
attr_writer :grade # setter saja
def initialize(nama, umur, id)
@nama = nama
@umur = umur
@id = id
end
end
s = Student.new("Andi", 20, 1001)
puts s.nama # Andi
s.nama = "Rina" # setter tersedia
puts s.id # 1001 (reader)
# s.id = 9999 # Error! id hanya reader
7. Array dan Hash
Array adalah kumpulan data terurut, sedangkan Hash adalah kumpulan data berupa pasangan key-value. Keduanya adalah struktur data paling penting di Ruby.
Array
# Membuat array
buah = ["apel", "mangga", "jeruk"]
angka = [1, 2, 3, 4, 5]
campuran = [1, "dua", 3.0, true, nil]
# Akses elemen
puts buah[0] # apel
puts buah[-1] # jeruk (elemen terakhir)
puts buah[1..2] # ["mangga", "jeruk"] (slice)
puts buah.first # apel
puts buah.last # jeruk
# Menambah elemen
buah.push("pisang") # Tambah di akhir
buah.unshift("anggur") # Tambah di awal
buah.insert(2, "lemon") # Tambah di posisi index 2
puts buah.inspect
# Menghapus elemen
buah.pop # Hapus elemen terakhir
buah.shift # Hapus elemen pertama
buah.delete("mangga") # Hapus berdasarkan nilai
puts buah.inspect
# Informasi array
puts buah.length # Jumlah elemen
puts buah.empty? # true jika kosong
puts buah.include?("apel") # true jika ada
# Iterasi
fruits = ["apel", "mangga", "jeruk"]
# .each β iterasi standar
fruits.each { |f| puts f }
# .each_with_index β dapat index juga
fruits.each_with_index do |f, i|
puts "#{i}: #{f}"
end
# .map β transformasi dan kembalikan array baru
angka = [1, 2, 3, 4, 5]
kuadrat = angka.map { |n| n ** 2 }
puts kuadrat.inspect # [1, 4, 9, 16, 25]
# .select β filter elemen
ganjil = angka.select { |n| n.odd? }
puts ganjil.inspect # [1, 3, 5]
# .reject β kebalikan select
genap = angka.reject { |n| n.odd? }
puts genap.inspect # [2, 4]
# .reduce / .inject β akumulasi
total = angka.reduce(0) { |sum, n| sum + n }
puts total # 15
# Atau gunakan shortcut:
puts angka.sum # 15
# .sort
numbers = [3, 1, 4, 1, 5, 9]
puts numbers.sort.inspect # [1, 1, 3, 4, 5, 9]
# .flatten β array multi-dimensi jadi flat
multi = [[1, 2], [3, 4], [5]]
puts multi.flatten.inspect # [1, 2, 3, 4, 5]
# .uniq β hapus duplikat
dups = [1, 2, 2, 3, 3, 3]
puts dups.uniq.inspect # [1, 2, 3]
# .compact β hapus nil
dengan_nil = [1, nil, 2, nil, 3]
puts dengan_nil.compact.inspect # [1, 2, 3]
Hash
# Membuat hash
# Symbol keys (recommended)
user = { nama: "Budi", umur: 25, kota: "Jakarta" }
# String keys
data = { "nama" => "Budi", "umur" => 25 }
# Akses nilai
puts user[:nama] # Budi
puts user[:umur] # 25
puts user[:kota] # Jakarta
# Mengubah / menambah nilai
user[:email] = "budi@email.com"
user[:umur] = 26
puts user.inspect
# Menghapus nilai
user.delete(:email)
puts user.inspect
# Iterasi hash
user.each do |key, value|
puts "#{key}: #{value}"
end
# .keys dan .values
puts user.keys.inspect # [:nama, :umur, :kota]
puts user.values.inspect # ["Budi", 26, "Jakarta"]
# .has_key? dan .has_value?
puts user.has_key?(:nama) # true
puts user.has_value?("Budi") # true
# .fetch β dengan default value
puts user.fetch(:nama, "Tidak diketahui") # Budi
puts user.fetch(:email, "Tidak diketahui") # Tidak diketahui
# .merge β menggabungkan hash
h1 = { a: 1, b: 2 }
h2 = { b: 3, c: 4 }
puts h1.merge(h2).inspect # {:a=>1, :b=>3, :c=>4}
# Hash default value
counter = Hash.new(0) # Default value = 0
"hello world".each_char do |c|
counter[c] += 1
end
puts counter.inspect
# {"h"=>1, "e"=>1, "l"=>3, "o"=>2, " "=>1, "w"=>1, "r"=>1, "d"=>1}
# Ruby 3.1+ β .filter_map, .tally
words = ["apple", "banana", "cherry", "avocado"]
result = words.filter_map { |w| w if w.start_with?("a") }
puts result.inspect # ["apple", "avocado"]
8. Block dan Iterator
Block adalah salah satu fitur paling powerful dan unik di Ruby. Block adalah potongan kode yang dapat diberikan ke method sebagai parameter. Block sangat umum digunakan untuk iterasi, callback, dan DSL (Domain Specific Language).
Jenis Block
# Block dengan do...end (untuk block multi-line)
[1, 2, 3].each do |n|
puts "Angka: #{n}"
end
# Block dengan { } (untuk block single-line)
[1, 2, 3].each { |n| puts "Angka: #{n}" }
# Block dengan parameter
[1, 2, 3].each_with_index do |value, index|
puts "Index #{index}: #{value}"
end
# Menggunakan yield β memanggil block dari dalam method
def say_hello
puts "Sebelum yield"
yield # Memanggil block yang diberikan
puts "Setelah yield"
end
say_hello { puts "Halo dari block!" }
# Output:
# Sebelum yield
# Halo dari block!
# Setelah yield
# yield dengan argumen
def proses(angka)
result = yield(angka)
puts "Hasil: #{result}"
end
proses(10) { |n| n * 2 } # Hasil: 20
# Block_given? β cek apakah block diberikan
def greet(name = "Teman")
if block_given?
yield(name)
else
puts "Halo, #{name}!"
end
end
greet("Budi") { |n| puts "Selamat datang, #{n}!" }
greet() # Halo, Teman!
Proc, Lambda, dan Closure
# Proc β objek yang menyimpan block
square = Proc.new { |n| n ** 2 }
# Atau syntax shorthand:
square = proc { |n| n ** 2 }
puts square.call(5) # 25
puts square.call(3) # 9
# Lambda β seperti Proc tapi lebih ketat
double = lambda { |n| n * 2 }
# Atau syntax lambda:
double = ->(n) { n * 2 }
puts double.call(5) # 10
puts double[3] # 6 (juga bisa pakai [])
# Perbedaan Proc vs Lambda:
# 1. Lambda memeriksa jumlah argumen, Proc tidak
# 2. Lambda return dari lambda, Proc return dari method pemanggil
# Menggunakan Proc/Lambda sebagai parameter
def apply_to_all(array, operation)
array.map(&operation)
end
angka = [1, 2, 3, 4, 5]
puts apply_to_all(angka, proc { |n| n * 2 }).inspect
# [2, 4, 6, 8, 10]
puts apply_to_all(angka, ->(n) { n ** 2 }).inspect
# [1, 4, 9, 16, 25]
# Variable-number of block parameters
def flexible_method
yield("Budi", 25, "Jakarta")
end
flexible_method do |*args|
puts args.inspect # ["Budi", 25, "Jakarta"]
end
Iterator Populer
# .each β iterasi dasar
["a", "b", "c"].each { |x| puts x }
# .each_with_index β dengan index
["a", "b", "c"].each_with_index { |x, i| puts "#{i}: #{x}" }
# .map / .collect β transformasi
[1, 2, 3].map { |n| n * 10 } # [10, 20, 30]
# .select / .filter β filter
(1..10).select { |n| n.even? } # [2, 4, 6, 8, 10]
# .reject β kebalikan select
(1..10).reject { |n| n.even? } # [1, 3, 5, 7, 9]
# .reduce / .inject β akumulasi
(1..5).reduce(:+) # 15
(1..5).reduce(1) { |acc, n| acc * n } # 120 (faktorial!)
# .any? / .all? / .none? β predicate iteration
[1, 2, 3].any? { |n| n > 2 } # true
[1, 2, 3].all? { |n| n > 0 } # true
[1, 2, 3].none? { |n| n > 10 } # true
# .find / .detect β cari elemen pertama yang cocok
(1..100).find { |n| n % 7 == 0 && n % 3 == 0 } # 21
# .flat_map β map + flatten
[[1, 2], [3, 4], [5]].flat_map { |a| a.map { |n| n * 2 } }
# [2, 4, 6, 8, 10]
# .group_by β kelompokkan
(1..10).group_by { |n| n.odd? ? "ganjil" : "genap" }
# {"ganjil"=>[1, 3, 5, 7, 9], "genap"=>[2, 4, 6, 8, 10]}
# .each_with_object
result = [1, 2, 3].each_with_object([]) do |n, arr|
arr << n * 10
end
puts result.inspect # [10, 20, 30]
9. Class dan Object
Ruby adalah bahasa Object-Oriented sepenuhnya. Semua data di Ruby adalah objek, termasuk angka, string, dan bahkan nil. Class mendefinisikan blueprint untuk membuat objek.
Class Dasar
# Class sederhana
class Hewan
attr_accessor :nama, :jenis
def initialize(nama, jenis)
@nama = nama # Instance variable
@jenis = jenis
end
def info
"#{nama} adalah seekor #{jenis}"
end
def suara
"..."
end
end
# Membuat objek
kucing = Hewan.new("Kitty", "kucing")
puts kucing.info # Kitty adalah seekor kucing
puts kucing.suara # ...
kucing.nama = "Mochi" # Setter tersedia (attr_accessor)
puts kucing.info # Mochi adalah seekor kucing
# Instance variable hanya bisa diakses di dalam class
# unless ada accessor method
puts kucing.instance_variables.inspect
# [:@nama, :@jenis]
Inheritance
# Inheritance β class turunan
class Hewan
attr_reader :nama
def initialize(nama)
@nama = nama
end
def info
"Saya adalah #{nama}"
end
def suara
raise NotImplementedError, "Harus di-override!"
end
end
class Kucing < Hewan
def suara
"Meow! π±"
end
def bermain
"#{nama} bermain dengan bola benang π§Ά"
end
end
class Anjing < Hewan
def suara
"Guk! π"
end
def bermain
"#{nama} bermain lempar tangkap πΎ"
end
end
kucing = Kucing.new("Kitty")
anjing = Anjing.new("Buddy")
puts kucing.info # Saya adalah Kitty
puts kucing.suara # Meow! π±
puts kucing.bermain # Kitty bermain dengan bola benang π§Ά
puts anjing.info # Saya adalah Buddy
puts anjing.suara # Guk! π
# Cek inheritance
puts Kucing.ancestors.inspect
# [Kucing, Hewan, Object, Kernel, BasicObject]
Method Visibility
# Tiga level visibility di Ruby:
# public β bisa diakses dari mana saja
# protected β hanya bisa diakses dari class yang sama
# private β hanya bisa diakses dari dalam class
class AkunBank
attr_reader :pemilik
def initialize(pemilik, saldo)
@pemilik = pemilik
@saldo = saldo
end
def info_publik
"Akun milik #{@pemilik}" # public
end
protected
def saldo_lengkap
"Saldo #{@pemilik}: Rp #{format('%.0f', @saldo)}" # protected
end
private
def validasi_pin(pin) # private
pin == 1234
end
end
akun = AkunBank.new("Budi", 1_000_000)
puts akun.info_publik # OK
# puts akun.saldo_lengkap # Error! protected
# puts akun.validasi_pin(1234) # Error! private
Class Methods dan Self
# Class method β dipanggil pada class, bukan instance
class Calculator
@@history = [] # Class variable
def initialize(value)
@value = value
end
def self.history
@@history
end
def self.hapus_history
@@history.clear
end
def tambah(lain)
result = @value + lain
Calculator.history << { aksi: :tambah, hasil: result }
result
end
end
# Menggunakan class method
calc = Calculator.new(10)
puts calc.tambah(5) # 15
puts calc.tambah(3) # 13
puts Calculator.history.inspect
# [{:aksi=>:tambah, :hasil=>15}, {:aksi=>:tambah, :hasil=>13}]
Calculator.hapus_history
puts Calculator.history.inspect # []
# self β referensi ke objek saat ini
class User
attr_reader :nama
def initialize(nama)
@nama = nama
end
def say_hello
puts "Halo, saya #{self}!" # self adalah objek User
end
def to_s
"User(#{nama})"
end
end
Comparable Module
# Include Comparable untuk mendapatkan metode perbandingan
class Mahasiswa
include Comparable
attr_reader :nama, :ipk
def initialize(nama, ipk)
@nama = nama
@ipk = ipk
end
def <=>(other)
ipk <=> other.ipk
end
def to_s
"#{nama} (IPK: #{ipk})"
end
end
mhs1 = Mahasiswa.new("Budi", 3.8)
mhs2 = Mahasiswa.new("Rina", 3.9)
mhs3 = Mahasiswa.new("Andi", 3.5)
# Comparable menyediakan: <, >, <=, >=, ==, between?
puts mhs1 < mhs2 # true
puts mhs1 > mhs3 # true
mahasiswa = [mhs1, mhs2, mhs3]
puts mahasiswa.sort.inspect
# [Andi (IPK: 3.5), Budi (IPK: 3.8), Rina (IPK: 3.9)]
10. Module dan Mixin
Module di Ruby adalah nama yang dapat dikelompokkan method dan constant. Module mirip dengan class tetapi tidak bisa diinstansiasi. Module digunakan untuk namespace dan mixin (membagikan method ke beberapa class).
Module Dasar
# Module sebagai Namespace
module Utilitas
VERSION = "1.0.0"
def self.info
"Utilitas v#{VERSION}"
end
end
puts Utilitas.info # Utilitas v1.0.0
puts Utilitas::VERSION # 1.0.0
# Module sebagai Mixin
module DapatBerjalan
def berjalan
"#{nama} sedang berjalan πΆ"
end
end
module DapatBerlari
def berlari
"#{nama} sedang berlari π"
end
end
class Manusia
include DapatBerjalan # Instance methods
include DapatBerlari
attr_reader :nama
def initialize(nama)
@nama = nama
end
end
budi = Manusia.new("Budi")
puts budi.berjalan # Budi sedang berjalan πΆ
puts budi.berlari # Budi sedang berlari π
# extend β untuk class methods
module InfoKelas
def info
"Saya adalah class #{name}"
end
end
class Produk
extend InfoKelas
end
puts Produk.info # Saya adalah class Produk
Include vs Extend vs Prepend
# include β menambahkan method sebagai INSTANCE method
module Greeting
def greet
"Halo dari include!"
end
end
class MyClass
include Greeting
end
MyClass.new.greet # OK
# extend β menambahkan method sebagai CLASS method
class AnotherClass
extend Greeting
end
AnotherClass.greet # OK
# AnotherClass.new.greet # Error!
# prepend β method module dipanggil SEBELUM method class
module Logging
def save
puts "Logging: save dipanggil"
super # Panggil method save dari class
end
end
class Document
def save
puts "Document disimpan!"
end
end
class LoggableDocument < Document
prepend Logging
end
LoggableDocument.new.save
# Logging: save dipanggil
# Document disimpan!
# Method Resolution Order (MRO)
puts LoggableDocument.ancestors.inspect
# [Logging, LoggableDocument, Document, Object, ...]
Module dengan Enumerable
# Include Enumerable untuk mendapatkan semua metode iterasi
class DaftarBelanja
include Enumerable
def initialize
@items = []
end
def <<(item)
@items << item
end
# Enumerable membutuhkan method each
def each(&block)
@items.each(&block)
end
# Sekarang kita punya semua method Enumerable:
# map, select, reject, any?, all?, find, reduce, sort, dll
end
belanja = DaftarBelanja.new
belanja << "Beras"
belanja << "Telur"
belanja << "Susu"
belanja << "Roti"
# Menggunakan Enumerable methods
puts belanja.sort.inspect
# ["Beras", "Roti", "Susu", "Telur"]
panjang = belanja.select { |item| item.length > 4 }
puts panjang.inspect # ["Beras", "Susu", "Roti"]
puts belanja.any? { |item| item.start_with?("T") } # true
puts belanja.count # 4
# to_s override
def to_s
@items.join(", ")
end
puts belanja # Beras, Telur, Susu, Roti
11. Manipulasi String
Ruby memiliki fitur manipulasi string yang sangat kaya dan elegan.
Interpolasi dan Escape
# String interpolation (hanya berfungsi dengan "")
nama = "Budi"
umur = 25
puts "Nama: #{nama}, Umur: #{umur}" # Nama: Budi, Umur: 25
puts "2 + 2 = #{2 + 2}" # 2 + 2 = 4
# Single quotes β tidak ada interpolasi
puts 'Nama: #{nama}' # Nama: #{nama} (literal)
# Escape characters
puts "Baris 1\nBaris 2" # Newline
puts "Tab\there" # Tab
puts "Quote: \"Halo\"" # Quote
puts "Backslash: \\" # Backslash
# Heredoc β string multi-baris
html = <<~HTML
<html>
<body>
<h1>#{nama}</h1>
</body>
</html>
HTML
# Raw string (tanpa escape)
path = %q(C:\Users\Nama\Documents) # Single
path = %Q(C:\Users\#{nama}\Documents) # Double (ada interpolation)
Method String Populer
teks = " Hello, Ruby World! "
# Ukuran
puts teks.length # 23
puts teks.empty? # false
# Case
puts teks.downcase # " hello, ruby world! "
puts teks.upcase # " HELLO, RUBY WORLD! "
puts "hello".capitalize # "Hello"
puts "hello".swapcase # "HELLO"
# Trim
puts teks.strip # "Hello, Ruby World!"
puts teks.lstrip # "Hello, Ruby World! "
puts teks.rstrip # " Hello, Ruby World!"
# Pencarian
puts teks.include?("Ruby") # true
puts teks.index("Ruby") # 9
puts teks.count("l") # 3
# Ganti
puts teks.gsub("Ruby", "Python") # " Hello, Python World! "
puts teks.strip.gsub(" ", "_") # "Hello,_Ruby_World!"
# Split dan Join
kalimat = "apel mangga jeruk pisang"
buah = kalimat.split(" ")
puts buah.inspect # ["apel", "mangga", "jeruk", "pisang"]
puts buah.join(", ") # "apel, mangga, jeruk, pisang"
# Start dengan, end dengan
puts "hello".start_with?("he") # true
puts "hello".end_with?("lo") # true
# Repeat
puts "Ha" * 3 # "HaHaHa"
# Pad
puts "42".rjust(5, "0") # "00042"
puts "halo".ljust(10, ".") # "halo......."
puts "hi".center(10, "-") # "----hi----"
# Encoding
puts "Ruby".encoding # UTF-8
puts "Ruby".bytesize # 4
12. Error Handling
Ruby menggunakan begin...rescue...ensure untuk menangani error. Ini mirip dengan try-catch di bahasa lain.
# begin...rescue...ensure
begin
result = 10 / 0
rescue ZeroDivisionError => e
puts "Error: #{e.message}"
puts "Class: #{e.class}"
ensure
puts "Ini selalu dieksekusi (cleanup)"
end
# Output:
# Error: divided by 0
# Class: ZeroDivisionError
# Ini selalu dieksekusi (cleanup)
# Multiple rescue
begin
# some code
data = JSON.parse("invalid json")
rescue ZeroDivisionError
puts "Pembagian dengan nol"
rescue JSON::ParserError
puts "JSON tidak valid"
rescue => e # Tangkap semua error lainnya
puts "Error lain: #{e.class} - #{e.message}"
end
# Rescue inline (single line)
def bagi(a, b)
a / b
rescue ZeroDivisionError
puts "Tidak bisa bagi dengan nol!"
0 # Return value saat error
end
# Raise β melempar error sendiri
def validasi_umur(umur)
raise ArgumentError, "Umur harus positif" if umur < 0
raise ArgumentError, "Umur tidak valid" unless umur.is_a?(Integer)
umur
end
# Custom error class
class InsufficientFundsError < StandardError
attr_reader :saldo, :dibutuhkan
def initialize(saldo, dibutuhkan)
@saldo = saldo
@dibutuhkan = dibutuhkan
super("Saldo tidak cukup. Saldo: Rp#{saldo}, Dibutuhkan: Rp#{dibutuhkan}")
end
end
def tarik_tunai(saldo, jumlah)
raise InsufficientFundsError.new(saldo, jumlah) if jumlah > saldo
saldo - jumlah
end
begin
sisa = tarik_tunai(100000, 150000)
rescue InsufficientFundsError => e
puts e.message
puts "Selisih: Rp#{e.dibutuhkan - e.saldo}"
end
13. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Ruby: