Senin, 08 September 2014

Dasar-Dasar Pemrograman Ruby

Dasar-Dasar Pemrograman Ruby

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 dengan
puts 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}"
Sumber-sumber:
·         Dokumentasi Fixnum
·         Techotopia: Ruby Operators
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
# 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
Ada juga case…when untuk mempersingkat if, elsif, dan else jika menggunakan ==
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)
Kamu juga bisa buat method dengan lebih dari satu parameter
# 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.
1.    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}"
}
2.    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" })



Tidak ada komentar:

Posting Komentar