├── .gitignore ├── .rvmrc ├── Question.md ├── Quiz.md ├── Readme.md ├── Session1.md ├── Session2.md ├── Session3.md └── Session4.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm 1.9.3@ruby_basic --create 2 | -------------------------------------------------------------------------------- /Question.md: -------------------------------------------------------------------------------- 1 | 2 | 1. Ruby itu bahasa pemrograman yang seperti apa? 3 | A. Strongly typed/Statically typed 4 | B. Strongly typed/Dynamically typed 5 | C. Weakly typed/Statically typed 6 | D. Weakly typed/Dynamically typed 7 | E. Tidak ada jawaban yang benar 8 | 9 | 2. Berikut ini yang merupakan tipe primitif di Ruby 10 | A. Integer 11 | B. String 12 | C. Float 13 | D. Char 14 | E. Tidak ada jawaban yang benar 15 | 16 | 3. Variabel yang diawali dengan huruf besar di Ruby 17 | A. Local variable 18 | B. Global variable 19 | C. Instance variable 20 | D. Class variable 21 | E. Tidak ada jawaban yang benar 22 | 23 | 3. Variabel yang diawali dengan tanda dolar `$` di Ruby 24 | A. Local variable 25 | B. Global variable 26 | C. Instance variable 27 | D. Class variable 28 | E. Tidak ada jawaban yang benar 29 | 30 | 4. Variabel yang diawali dengan simbol `@@` di Ruby 31 | A. Local variable 32 | B. Global variable 33 | C. Instance variable 34 | D. Class variable 35 | E. Tidak ada jawaban yang benar 36 | 37 | 5. Variabel yang diawali dengan simbol `@` di Ruby 38 | A. Local variable 39 | B. Global variable 40 | C. Instance variable 41 | D. Class variable 42 | E. Tidak ada jawaban yang benar 43 | -------------------------------------------------------------------------------- /Quiz.md: -------------------------------------------------------------------------------- 1 | # Quiz 2 | 3 | ## Tuliskan output dari kode berikut: 4 | 1. ```ruby 5 | 1 + '0' 6 | ``` 7 | 8 | 2. ```ruby 9 | puts "i love ruby" =~ /ruby/ 10 | ``` 11 | 12 | 3. ```ruby 13 | a = { 14 | :x => 20, 15 | :y => 70 16 | } 17 | b = { 18 | :y => 100, 19 | :z => 35 20 | } 21 | c = {:j => 30, :k => 45} 22 | 23 | puts a.merge(b)[:y] + c.delete(:k) 24 | ``` 25 | 26 | 4. ```ruby 27 | class ABC 28 | def initialize 29 | x = 0 30 | end 31 | 32 | def y 33 | x + 1 34 | end 35 | end 36 | 37 | a = ABC.new 38 | puts a.y 39 | ``` 40 | 41 | 5. ```ruby 42 | module A 43 | def x 44 | puts "Ax" 45 | end 46 | 47 | def y 48 | puts "Ay" 49 | end 50 | end 51 | 52 | module B 53 | def y 54 | puts "By" 55 | end 56 | 57 | def z 58 | puts "Bz" 59 | end 60 | end 61 | 62 | module C 63 | def x 64 | puts "Cy" 65 | end 66 | 67 | def z 68 | puts "Cz" 69 | end 70 | end 71 | 72 | class D 73 | include A 74 | include B 75 | include C 76 | 77 | def x 78 | puts "Dx" 79 | end 80 | end 81 | 82 | d = D.new 83 | d.x 84 | d.y 85 | d.z 86 | ``` 87 | 88 | 6. ```ruby 89 | @a = 10 90 | 91 | def m 92 | return 1 if @a > 4 93 | 2 94 | rescue 95 | 3 96 | end 97 | 98 | puts m 99 | ``` 100 | 101 | 7. ```ruby 102 | def x(y) 103 | if block_given? 104 | y + 3 105 | else 106 | 5 107 | end 108 | end 109 | 110 | z = x 5 do |c| 111 | c + 5 112 | end 113 | 114 | puts z 115 | ``` 116 | 117 | 8. ```ruby 118 | class String 119 | def upcase 120 | "omg" 121 | end 122 | end 123 | 124 | puts "hello".upcase! 125 | ``` 126 | 127 | 9. ```ruby 128 | module M 129 | def method_missing(*args) 130 | "M" 131 | end 132 | end 133 | 134 | class C 135 | include M 136 | 137 | def n 138 | "N" 139 | end 140 | end 141 | 142 | c = C.new 143 | puts c.n + c.m 144 | ``` 145 | 146 | ## Berapa jumlah failed test yang terjadi: 147 | 148 | 10. ```ruby 149 | require 'minitest/autorun' 150 | 151 | class A 152 | def x 153 | "X" 154 | end 155 | 156 | def y 157 | 5 158 | end 159 | 160 | def z 161 | raise "Z" 162 | end 163 | end 164 | 165 | describe A do 166 | before do 167 | @a = A.new 168 | end 169 | 170 | it "should do x" do 171 | @a.x.must_equal "X" 172 | end 173 | 174 | it "should do y" do 175 | @a.y.wont_be_nil 176 | end 177 | 178 | it "should do z" do 179 | @a.z.must_equal "Z" 180 | end 181 | end 182 | ``` 183 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Pemrograman Ruby 2 | 3 | ## Persiapan: 4 | 5 | Komputer dengan sistem operasi unix-like, seperti Linux atau MacOS. 6 | 7 | Kami merekomendasikan ubuntu 11.10. 8 | 9 | install ruby dengan perintah `sudo apt-get install ruby` 10 | 11 | ## Session 1: Basic Ruby 12 | 13 | * Ruby Overview 14 | * Menjalankan Ruby 15 | * Syntax dan Idiom 16 | * Object-Oriented in Ruby: Classes, Attributes, Methods 17 | * String Type and Operations 18 | * Numeric 19 | * Boolean 20 | * Conditional Constructs 21 | * Arrays 22 | * Code Blocks 23 | * Ranges 24 | * Regular Expressions 25 | * Symbols 26 | * Hashes 27 | 28 | ## Session 2: OOP with Ruby 29 | 30 | * Advanced OOP in Ruby 31 | * Instance Variables 32 | * Accessors 33 | * Class Variables 34 | * Class Methods 35 | * Inheritance 36 | * Access Control 37 | * Modules 38 | * Variable 39 | 40 | ## Session 3: Advanced Topic 41 | 42 | * Exceptions 43 | * Advanced Blocks 44 | * Classes as Objects 45 | * Metaprogramming 46 | * I/O 47 | 48 | ## Session 4: Testing 49 | 50 | * Libraries 51 | * Instalasi & Menggunakan Gems 52 | * Bundler 53 | * Packaging Programs and Libraries for Distribution 54 | * Testing 55 | * Unit Testing with Minitest 56 | * Introduction to TDD 57 | -------------------------------------------------------------------------------- /Session1.md: -------------------------------------------------------------------------------- 1 | # Session 1: Dasar Ruby 2 | 3 | ## Ruby Overview 4 | 5 | Ruby adalah bahasa pemrograman berorientasi object murni yang dikembangkan oleh Yukihiro Matsumoto (Matz) pada tahun 1993. 6 | Ruby merupakan bahasa interpreted, yang berarti untuk menjalankan ruby tidak perlu dicompile, tetapi cukup dijalankan dalam interpreternya. 7 | Ruby juga merupakan bahasa dinamis. Kita tidak perlu melakukan deklarasi variable, tetapi cukup melakukan assignment secara langsung. 8 | 9 | Ruby dibuat dengan tujuan untuk membuat programmer lebih bahagia. Artinya ruby dirancang untuk mempermudah kerja programmer. 10 | Programmer tidak perlu melakukan banyak tugas yang dapat dilakukan oleh komputer, sehingga programmer menjadi lebih produktif. 11 | Keunggulan utama dari ruby adalah bahasa yang sangat ekspresif, yang mempermudah programmer untuk mengubah dari ide menjadi kode program. 12 | 13 | Penggunaan ruby yang paling umum adalah untuk pemrograman web, dengan framework ruby on rails. 14 | Tetapi ruby adalah bahasa pemrograman umum yang dapat digunakan untuk semua keperluan programming, 15 | dari aplikasi web, desktop, scripting, hingga aplikasi mobile. 16 | 17 | Ruby merupakan bahasa object oriented murni. Dalam ruby, tidak ada tipe primitif. 18 | Semua adalah object, termasuk integer, string, array, class dan sebagainya. 19 | 20 | Berikut ini adalah contoh program hello world di ruby: 21 | 22 | ```ruby 23 | puts "Hello world" 24 | ``` 25 | 26 | ## Menjalankan Ruby 27 | 28 | Cara paling mudah untuk mencoba ruby adalah dengan menggunakan irb (interactive ruby). 29 | 30 | ``` 31 | $ irb 32 | > 3 + 5 33 | => 8 34 | > puts "hello " * 3 35 | hello hello hello 36 | => nil 37 | ``` 38 | 39 | Irb sangat berguna untuk mencoba kode dan melihat hasilnya dengan cepat. 40 | Namun untuk membuat program yang sebenarnya, kita akan menyimpan kode ruby kita dalam file, yang biasanya berekstensi .rb. 41 | 42 | ``` ruby 43 | # file: hello.rb 44 | 4.times do 45 | puts "hello" 46 | end 47 | ``` 48 | 49 | kemudian kita jalankan dengan perintah `ruby ` 50 | 51 | ``` 52 | $ ruby hello.rb 53 | hello 54 | hello 55 | hello 56 | hello 57 | ``` 58 | ## Syntax dan Idiom 59 | 60 | Program yang ditulis dengan ruby pada umumnya mudah dibaca. Hal ini dikarenakan ruby memiliki syntax yang bersih dan sederhana. 61 | Readability program juga terbantu jika programmer mengikuti idiom yang umum digunakan dalam ruby. 62 | 63 | Berikut ini adalah contoh program sederhana dalam ruby: 64 | 65 | ``` ruby 66 | class Person 67 | attr_accessor :first_name, :last_name, :age 68 | 69 | def initialize(first_name, last_name) 70 | @first_name = first_name 71 | @last_name = last_name 72 | end 73 | 74 | def fullname 75 | @first_name + " " + @last_name 76 | end 77 | 78 | def mature? 79 | @age > 17 80 | end 81 | 82 | def increase_age! 83 | @age += 1 84 | end 85 | end 86 | 87 | person = Person.new "Slamet", "Riyadi" 88 | person.age = 17 89 | person.full_name # "Slamet Riyadi" 90 | person.increase_age! # @age == 18 91 | person.mature? # true 92 | ``` 93 | 94 | Untuk membuat kelas, kita menggunakan kata kunci `class` diikuti dengan nama kelas. Nama kelas dalam ruby harus dimulai dengan huruf kapital. 95 | Idiom yang biasa dipakai adalah menggunakan *CamelCase* untuk nama kelas. 96 | 97 | contoh: `PurchasedItem`, `ProductsInventory` 98 | 99 | Kata kunci `def` digunakan untuk mendefinisikan method didalam suatu kelas atau modul. 100 | Pada umumnya, kita menggunakan huruf kecil dan *underscore* (_) sebagai nama method (biasa disebut *snake_case*). 101 | Nama method dapat mempunyai tanda baca seperti `?, !, =` pada bagian akhir. 102 | Tanda tanya (?) biasa digunakan dalam nama method yang mereturn boolean, sedangkan tanda seru (!) digunakan dalam 103 | method yang dianggap berbahaya, biasanya method yang dapat mengubah nilai. 104 | 105 | contoh: `products_list`, `buy!`, `available?` 106 | 107 | Penamaan menggunakan *snake_case* digunakan hampir di semua hal dalam ruby selain nama kelas dan konstant. 108 | Instant variable selalu diawali dengan tanda `@`. Object diinisiasi dengan memanggil method `new` pada kelasnya. 109 | Pada umumnya programmer ruby selalu menggunakan indentasi 2 spasi dan tidak pernah menggunakan indentasi tab. 110 | 111 | ## Object-Oriented in Ruby: Classes, Attributes, Methods 112 | 113 | Ruby adalah bahasa object oriented murni. Semuanya dari integer hingga string adalah object. 114 | Setiap object memiliki *methods* yang dapat dipanggil untuk melakukan berbagai fungsi. 115 | Untuk memanggil method, kita menggunakan syntax titik (.) yang diikuti oleh nama methodnya. 116 | Contohnya, jika kita ingin mengubah kalimat "hello world" menjadi huruf kapital, kita bisa memanggil method *upcase* 117 | 118 | ```ruby 119 | puts "hello world".upcase 120 | ``` 121 | 122 | Beberapa method, seperti *puts* dan *gets* dapat dipanggil dimanapun dan tidak perlu digabungkan dengan object tertentu. 123 | Method - method ini ada di dalam modul *Kernel* bawaan ruby, yang di *include* di dalam semua object ruby. 124 | Ketika kita menjalankan aplikasi ruby, sebuah object dengan nama *main* dibuat secara otomatis dan memberikan kita akses 125 | ke semua method dalam module *Kernel* 126 | 127 | ## String Type and Operations 128 | 129 | String adalah object ruby yang berfungsi memanipulasi rangkaian byte, yang pada umumnya mereprensentasikan huruf - huruf 130 | dalam suatu kalimat. Ruby memiliki kelas built-in yang bernama `String` yang memiliki beberapa method yang sering kita 131 | gunakan dalam memprogram ruby. 132 | 133 | Berikut ini adalah fungsi - fungsi yang terkait dengan String dalam ruby: 134 | 135 | ### String declaration 136 | 137 | Pada umumnya sebuah string dideklarasikan dengan rangkaian huruf yang dibatasi oleh tanda 138 | petik ganda (") atau tunggal ('). 139 | 140 | contoh: `"ini adalah sebuah string"`, `'ini juga'` 141 | 142 | String juga dapat dideklarasikan dengan menggunakan *general delimiter* berupa yang diawali oleh 143 | `%`, `%Q`, atau `%q`. 144 | 145 | contoh: 146 | 147 | ```ruby 148 | %{ String menggunakan general delimiter } 149 | %Q{ String menggunakan general delimiter } 150 | ``` 151 | 152 | Untuk membuat string lebih dari satu baris, akan lebih mudah menggunakan syntax sebagai berikut: 153 | 154 | ```ruby 155 | multiline_string = <<-STR 156 | ini adalah string 157 | lebih dari satu baris 158 | STR 159 | ``` 160 | 161 | ### Expression subtitution 162 | 163 | Expression subtitution adalah suatu cara untuk menggabungkan hasil dari suatu ekspresi ruby ke dalam suatu string 164 | menggunakan #{ dan }: 165 | 166 | ```ruby 167 | name = "Ruby" 168 | a = 7 169 | b = 3 170 | puts "my name is #{name}" # my name is Ruby 171 | puts "#{a} + #{b} = #{ a + b }" # 7 + 3 = 10 172 | ``` 173 | 174 | ### String methods 175 | 176 | Berikut ini adalah beberapa method yang dimiliki String object yang sering kita gunakan: 177 | 178 | * `str + other_str` 179 | menggabungkan other_str ke str, menghasilkan object baru hasil gabungan kedua string tersebut. 180 | 181 | * `str << other_str` 182 | menggabungkan other_str ke str, mengubah object str (tidak menghasilkan object baru). 183 | 184 | * `str <=> other_str` 185 | membandingkan dua string, menghasilkan -1 jika str lebih kecil dari other_str, 1 jika str 186 | lebih besar dari str, dan 0 jika str sama dengan other_str 187 | 188 | * `str == other_str` 189 | membandingkan kesamaan dua string, menghasilkan `true` jika sama, `false` jika tidak sama. 190 | 191 | * `str =~ regex` 192 | membandingkan string dengan regular expression, menghasilkan posisi pertama kesesuaian jika ada, 193 | atau 0 jika tidak sesuai. 194 | 195 | * `str.capitalize` 196 | mengubah huruf pertama menjadi huruf kapital, menghasilkan object baru. 197 | 198 | * `str.capitalize!` 199 | mengubah huruf pertama menjadi huruf kapital dengan mengubah object yang ada. 200 | 201 | * `str.upcase` 202 | mengubah semua huruf menjadi huruf kapital, menghasilkan object baru. 203 | 204 | * `str.upcase!` 205 | mengubah semua huruf menjadi huruf kapital dengan mengubah object yang ada. 206 | 207 | * `str.length` 208 | menghasilkan panjang string. 209 | 210 | * `str.strip` 211 | menghapus whitespace yang ada di depan dan di belakang string. 212 | 213 | ## Numeric 214 | 215 | Dalam ruby, angka bukanlah primitive. Setiap angka adalah object, instance dari salah satu kelas 216 | numeric ruby. `Numeric` adalah kelas basis untuk angka di ruby. Kelas `Fixnum` digunakan untuk 217 | integer, `Float` untuk angka pecahan, dan `Bignum` untuk angka integer yang lebih besar. 218 | 219 | Konversi antara angka `Fixnum` dan `Bignum` terjadi secara otomatis. Ketika suatu angka tidak 220 | dapat disimpan dalam `Fixnum`, akan secara otomatis diubah ke `Bignum`, sehingga kita sebagai 221 | programmer tidak perlu memikirkannya. 222 | 223 | contoh: 224 | 225 | ```ruby 226 | 2411 # integer, Fixnum 227 | 2_411 # integer, Fixnum, underscore diabaikan 228 | 241.1 # pecahan, Float 229 | 3.7e4 # scientific notation, Float 230 | 3E4 # scientific notation, Float 231 | 3E-4 # scientific notation, dengan tanda sebelum exponent 232 | 0444 # octal, Fixnum 233 | 0xfff # hexadecimal, Fixnum 234 | 0b1101 # binary, Fixnum 235 | 4567832704 # integer, Bignum 236 | ``` 237 | 238 | ## Boolean 239 | 240 | Ruby memiliki nilai boolean `true` dan `false`, yang merupakan object dari kelas `TrueClass` dan `FalseClass`. 241 | Dalam ruby, semua nilai selain `false` dan `nil` dianggap bernilai true dan dapat digunakan dalam operasi 242 | boolean, seperti conditional, `and`, `or` dan sebagainya. 243 | 244 | ## Conditional Constructs 245 | 246 | Conditional statement mengecek apakah suatu ekspresi bernilai benar atau salah dan menjalankan logic sesuai 247 | dengan hasil dari ekspresi tersebut. 248 | 249 | ### If statement 250 | 251 | If statement diawali dengan keyword `if` dan diakhiri dengan keyword `end`. 252 | 253 | ```ruby 254 | if 3 > 2 255 | puts "Tiga lebih besar dari dua" 256 | end 257 | ``` 258 | 259 | Operator `!` membalikkan nilai `true / false` suatu ekspresi. 260 | 261 | ```ruby 262 | if !(x > y) 263 | puts "X tidak lebih besar dari y" 264 | end 265 | ``` 266 | 267 | Kita dapat menggunakan operasi boolean dalam if statement untuk mengecek dua ekspresi atau lebih 268 | menggunakan `&& (and)` dan `|| (or)`. 269 | 270 | ```ruby 271 | if ruby == "great" && programming == fun 272 | puts "I love programming with ruby" 273 | end 274 | ``` 275 | 276 | Jika ekspresi cukup pendek, kita dapat meletakkan if statement di belakang sebagai modifier. 277 | 278 | ```ruby 279 | puts "Tiga lebih besar dari dua" if 3 > 2 280 | ``` 281 | 282 | `else` dan `elsif` dapat ditambahkan sebagai opsi jika statement `if` tidak benar. 283 | 284 | ```ruby 285 | if x > y 286 | puts "x lebih besar dari y" 287 | elsif x < y 288 | puts "x lebih kecil dari y" 289 | else 290 | puts "x sama dengan y" 291 | end 292 | ``` 293 | 294 | Jika kita mengecek negasi dari suatu expresi, akan lebih jelas jika kita memakai `unless` daripada menggunakan operator `!` 295 | 296 | ```ruby 297 | unless x == y 298 | puts "x tidak sama dengan y" 299 | end 300 | ``` 301 | 302 | Seperti `if`, `unless` juga dapat kita letakkan di belakang sebagai modifier. 303 | 304 | ```ruby 305 | puts "Tiga tidak lebih besar dari dua" unless 3 > 2 306 | ``` 307 | 308 | ### While statement 309 | 310 | While loop digunakan untuk mengeksekusi suatu blok kode selama nilai conditionalnya `true`. 311 | 312 | ```ruby 313 | i = 0 314 | while i < 10 315 | puts "hello" 316 | i += 1 317 | end 318 | ``` 319 | 320 | ### Until statement 321 | 322 | Sebagaimana `unless` adalah negasi dari `if`, statement `until` adalah negasi dari `while`, yaitu 323 | akan mengeksekusi blok kode sampai nilai conditionalnya menjadi `true`. 324 | 325 | ```ruby 326 | i = 0 327 | until i >= 10 328 | puts "hello" 329 | i += 1 330 | end 331 | ``` 332 | 333 | 334 | Pada prakteknya, kita akan sangat jarang menggunakan `while` dan `until` untuk melakukan loop. 335 | Kita akan lebih sering melakukan iterasi menggunakan method `each` yang dimiliki suatu array / koleksi. 336 | 337 | ### Case statement 338 | 339 | Statement `case` dan `when` dalam ruby memberikan cara untuk mengekspresikan conditional logic dalam bentuk 340 | yang sangat ringkas. `case` mirip dengan `switch` dalam bahasa pemrograman lain, tetapi `case` dapat 341 | mengecek semua tipe object yang dapat dibandingkan kesamaannya atau ekuivalensinya. 342 | 343 | Menggunakan `case` statement lebih ringkas daripada menggunakan `if else` karena kita berasumsi membandingkan 344 | kesamaan dengan `==`. 345 | 346 | ```ruby 347 | lang = "fr" 348 | dog = case lang 349 | when "en" 350 | "dog" 351 | when "es" 352 | "perro" 353 | when "fr" 354 | "chien" 355 | when "de" 356 | "Hund" 357 | else 358 | "dog" 359 | end 360 | ``` 361 | 362 | `case` dapat digunakan untuk melakukan perbandingan nilai dalam range tertentu 363 | 364 | ```ruby 365 | scale = 8 366 | case scale 367 | when 0 368 | puts "lowest" 369 | when 1..3 370 | puts "medium-low" 371 | when 4..5 372 | puts "medium" 373 | when 6..7 374 | puts "medium-high" 375 | when 8..9 376 | puts "high" 377 | when 10 378 | puts "highest" 379 | else 380 | "oputsff scale" 381 | end 382 | ``` 383 | 384 | ### Operator ternary 385 | 386 | Operator ternary (?:) adalah struktur yang diwarisikan dari C ke ruby. Operator ini merupakan bentuk pendek 387 | dari `if else` statement. 388 | 389 | ```ruby 390 | size = length > 100 ? "Big" : "Small" 391 | ``` 392 | 393 | ## Arrays 394 | 395 | Array adalah salah satu kelas bawaan ruby. Array adalah suatu koleksi object yang berurutan dan dapat 396 | diakses berdasarkan indexnya. Dalam ruby, array dapat menyimpan semua object seperti String, Fixnum, 397 | Hash bahkan array yang lain. Setiap elemen di dalam array diasosiasikan dan diakses dengan index 398 | tertentu. Elemen - elemen array secara otomatis diindex dengan angka dimulain dari 0. 399 | Kita dapat mengakses elemen terakhir dari array dengan menggunakan index -1, 400 | kedua dari belakang dengan -2 dan seterusnya. Ukuran array di ruby dinamis dan dapat bertambah sesuai 401 | dengan kebutuhan secara otomatis. 402 | 403 | ### Inisiasi array 404 | 405 | Ada beberapa cara untuk membuat / menginisiasi suatu array. Yang pertama adalah dengan memanggil method 406 | `new` pada kelas `Array` 407 | 408 | ```ruby 409 | months = Array.new 410 | ``` 411 | 412 | Kita dapat menentukan panjang awal suatu array ketika inisiasi. 413 | 414 | ```ruby 415 | months = Array.new 12 416 | ``` 417 | Array `months` sekarang memiliki panjang 12. 418 | 419 | Kita juga dapat melihat berapa panjang dari sebuah array. 420 | 421 | ```ruby 422 | months.size # 12 423 | #atau 424 | months.length # 12 425 | ``` 426 | 427 | Tetapi cara yang paling mudah dan paling umum digunakan untuk menginisiasi sebuah array adalah dengan 428 | menggunakan literal `[]` dan mengisi elemennya secara langsung. 429 | 430 | ```ruby 431 | months = ["January", "February", "March"] 432 | ``` 433 | 434 | ### Array methods 435 | 436 | Berikut ini adalah beberapa method penting yang sering kita pakai: 437 | 438 | * `array + other_array` 439 | mereturn array baru dengan menggabungkan kedua array. 440 | 441 | * `array - other_array` 442 | mereturn array baru dengan menghapus semua elemen `array` yang muncul di `other_array`. 443 | 444 | * `array << object` 445 | memasukkan `object` ke akhir array. 446 | 447 | * `array == other_array` 448 | mengecek apakah `array` memiliki elemen yang sama (yang masing-masing dibandingkan dengan method `==`) 449 | dengan `other_array` 450 | 451 | * `array <=> other_array` 452 | mereturn integer (-1, 0 atau 1) berdasarkan perbandingan elemen-elemen dalam kedua array 453 | 454 | * `array[index]` 455 | mereturn elemen pada `index`, menghasilkan nil jika tidak ada elemen pada index tersebut. 456 | 457 | * `array.each{|item| block}` 458 | menjalankan block untuk setiap elemen array, menggunakan elemen array tersebut sebagai parameter. 459 | 460 | * `array.map{|item| block}` 461 | menjalankan block untuk setiap elemen array, dan menghasilkan array baru dengan elemen hasil eksekusi blok tersebut. 462 | 463 | ## Code Blocks 464 | 465 | Sebuah _block_ dapat dianggap sebagai sebuah method yang tidak memiliki nama. 466 | Block dalam ruby dapat ditulis di dalam _brackets_ `{...}` atau `do...end`. 467 | Konsep block sering dipakai dalam ruby, misalnya dalam beberapa method milik array. 468 | 469 | ```ruby 470 | [1,2,3].each do |item| 471 | puts item 472 | end 473 | ``` 474 | 475 | Block juga berperilaku sebagai _closure_, yaitu kode dalam sebuah block dapat mengakses variabel diluarnya, 476 | tetapi kode di luar block tidak dapat mengakses variabel lokal dalam block tersebut. 477 | 478 | ```ruby 479 | prefix = "print " 480 | [1,2,3].each do |item| 481 | puts prefix 482 | puts item 483 | end 484 | 485 | puts item # error 486 | ``` 487 | 488 | ## Ranges 489 | 490 | _Range_ memberikan cara mudah untuk merepresentasikan urutan alfanumerik (angka dan huruf). 491 | Range dapat digunakan sebagai sekuens maupun untuk pengecekan interval. 492 | 493 | ```ruby 494 | one_to_ten = 1..10 495 | a_to_z = "a".."z" 496 | a0_to_z9 = "a0".."z9" 497 | ``` 498 | 499 | ### Range Sebagai Sekuens 500 | 501 | Range dapat diperlakukan sebagai array dan diiterasi: 502 | 503 | ```ruby 504 | (1..20).each do |num| 505 | puts num 506 | end 507 | ``` 508 | 509 | Ukuran langkah tiap satuan item dapat ditentukan dengan method `step` 510 | 511 | ```ruby 512 | (1..20).step(3).each do |num| 513 | puts num 514 | end 515 | ``` 516 | 517 | ### Range Sebagai Interval 518 | 519 | Range dapat digunakan untuk menentukan apakah suatu angka/string termasuk dalam interval tertentu 520 | 521 | ```ruby 522 | (1..20) === 22 # => false 523 | ``` 524 | 525 | Ini berarti range dapat digunakan dengan mudah dalam statement `case...when` 526 | 527 | ```ruby 528 | num = 9001 529 | 530 | case num 531 | when 1..10 532 | puts "Below ten" 533 | when 10..9000 534 | puts "Below nine thousand" 535 | else 536 | puts "Over nine thousaaaand!!!" 537 | end 538 | ``` 539 | 540 | ## Regular Expressions 541 | 542 | _Regular Expression_ dalam ruby ditangani oleh kelas `Regexp`. 543 | Untuk membentuk regular expression, sintaks yang digunakan sama dengan Perl. 544 | Regular expression dalam ruby juga memiliki fitur string interpolation. 545 | 546 | ```ruby 547 | movie_title_regexp = /^the/i 548 | 549 | string = "the" 550 | also_movie_title_regexp = /^#{string}/i # => /^the/i 551 | ``` 552 | 553 | Untuk mencocokan pola regular expression dengan sebuah string, bisa menggunakan method `=~` atau `[]` dari string. 554 | `=~` mengembalikan indeks pola yang pertama kali cocok, sedangkan `[]` mengembalikan substring yang cocok. 555 | 556 | ```ruby 557 | has_and = /and/i 558 | 559 | "Sand Man" =~ has_and # => 1 560 | "Sand Man"[has_and] # => "and" 561 | ``` 562 | 563 | ## Symbols 564 | 565 | Ruby memiliki object spesial yang bernama *symbol*. Symbol selalu diawali dengan titik dua `:`, 566 | seperti `:indonesia`. Hanya memiliki satu copy untuk setiap symbol, sehingga symbol yang sama 567 | pasti memiliki object yang sama. 568 | 569 | Symbol biasanya digunakan sebagai `key` atau indentifier dalam hash atau object ruby. 570 | 571 | ## Hashes 572 | 573 | Hash adalah koleksi pasangan `key-value` yang dalam ruby memiliki syntax sebagai berikut: 574 | 575 | ```ruby 576 | my_hash = { :name => "Nugroho", :age => 25 } 577 | ``` 578 | 579 | Hash mirip seperti array, tetapi jika array diindex dengan integer yang dimulai dari 0, hash 580 | diindex dengan object ruby. Semua object dalam ruby dapat dijadikan key ataupun value dalam 581 | hash. Tetapi pada umumnya kita lebih sering menggunakan symbol atau string sebagai key dari 582 | sebuah hash. 583 | 584 | Keys dalam hash harus unik. Jika kita mengakses index hash yang tidak ada, kita akan mendapatkan 585 | nilai `nil`. 586 | 587 | ### Inisiasi Hash 588 | 589 | Untuk menginisiasi sebuah hash, kita dapat memanggil method new dari kelas `Hash`: 590 | 591 | ```ruby 592 | my_hash = Hash.new 593 | ``` 594 | 595 | namun pada umumnya kita lebih sering membuat hash dengan literal hash sebagai berikut: 596 | 597 | 598 | ```ruby 599 | my_hash = {} 600 | ``` 601 | 602 | ### Hash methods 603 | 604 | Berikut ini adalah beberapa method hash yang sering kita gunakan: 605 | 606 | * `hash.[key]` digunakan untuk mengakses value hash dengan `key` tertentu. Akan mereturn 607 | object value jika ditemukan, atau `nil` jika tidak ditemukan. 608 | 609 | * `hash.clear` menghapus semua key dan value dari hash tersebut. 610 | 611 | * `hash.delete(key)` menghapus key-value dengan `key` tertentu. Akan mereturn value tersebut. 612 | 613 | * `hash.delete_if { |key,value| block }` menghapus key-value jika evaluasi `block` menghasilkan 614 | nilai true. 615 | 616 | * `hash.each { |key,value| block }` melakukan iterasi dan mengevaluasi block untuk semua key-value. 617 | 618 | * `hash.keys` menghasilkan array dari semua `key` dalam hash tersebut. 619 | 620 | * `hash.merge(another_hash)` menghasilkan hash baru yang merupakan gabungan kedua hash. Jika ada 621 | key yang sama, akan di override oleh nilai dari `another_hash`. 622 | -------------------------------------------------------------------------------- /Session2.md: -------------------------------------------------------------------------------- 1 | # Session 2: OOP with Ruby 2 | 3 | ## Overview 4 | 5 | Seperti yang telah disebutkan sebelumnya, Ruby merupakan bahasa pemrograman yang berorientasi objek. Semua yang bisa kita manipulasi di Ruby adalah sebuah objek. 6 | 7 | Di dalam pemrograman berorientasi objek, sebuah kelas memuat berbagai properti, seperti method dan variabel. Kelas bisa mewarisi properti dari kelas pendahulu (parent class) atau superclass nya, sehingga membentuk hierarki kelas dengan base class di tempat paling atas. Kelas paling atas (base class) di Ruby adalah `Object`. 8 | 9 | Sebuah kelas didefinisikan dengan keyword `class`, dan diakhiri dengan sebuah `end`. 10 | 11 | ```ruby 12 | class Hello 13 | def initialize( name ) 14 | @name = name 15 | end 16 | 17 | def hello_txt 18 | puts "Hello, " + @name + "!" 19 | end 20 | end 21 | 22 | hi = Hello.new("World") 23 | hi.hello_txt # => Hello, World! 24 | ``` 25 | 26 | Method `initialize` pada Ruby merupakan constructor, yang otomatis akan dieksekusi pertama kali setelah objek kelas tersebut diciptakan. Pada contoh di atas, method `initialize` akan mendefinisikan sebuah instance variable `@name` dan meng-assign-nya dengan argumen yang dimasukkan. 27 | 28 | 29 | ## Instance Variables 30 | 31 | Instance variabel adalah variabel yang ada di dalam instance sebuah kelas, dan cakupannya terbatas. Sebuah instance variable diawali dengan tanda `@`, seperti instance variable pada contoh sebelumnya `@name`. Kita bisa mendefinisikan sebuah instance variable di dalam atau di luar sebuah method. Namun, kita hanya bisa mengaksesnya dari luar objek dengan menggunakan method accessor: getter dan setter. 32 | 33 | ```ruby 34 | class Hello 35 | def initialize( name ) 36 | @name = name 37 | end 38 | 39 | def hello_txt 40 | puts "Hello, " + @name + "!" 41 | end 42 | 43 | def name 44 | @name 45 | end 46 | 47 | def name=(value) 48 | @name = value 49 | end 50 | end 51 | 52 | hi = Hello.new("World") 53 | hi.name # => World 54 | hi.name = "CCBI" 55 | hi.name # => CCBI 56 | ``` 57 | 58 | 59 | ## Accessors 60 | 61 | Ruby menyederhanakan pembuatan getter dan setter secara meta-programming dari kelas `Module`, yakni menggunakan method `attr`, `attr_reader`, `attr_writer` dan `attr_accessor`. 62 | 63 | Method `attr` akan membuat sebuah getter. Jika argumen keduanya `true`, ia juga akan membuat sebuah setter. 64 | 65 | ```ruby 66 | class Bird 67 | attr :chirp, true 68 | end 69 | 70 | Bird.instance_methods - Object.instance_methods # => ["chirp","chirp="] 71 | 72 | bird = Bird.new 73 | bird.chirp = "Tweet!" 74 | bird.chirp # => Tweet! 75 | ``` 76 | 77 | Method `attr_reader` akan menciptakan getter, sedangkan method `attr_writer` akan menciptakan setter. 78 | 79 | ```ruby 80 | class Bird 81 | attr_reader :chirp # getter 82 | attr_writer :chirp # setter 83 | end 84 | 85 | Bird.instance_methods - Object.instance_methods # => ["chirp","chirp="] 86 | ``` 87 | 88 | Method `attr_accessor` akan memberikan efek yang sama seperti jika memanggil `attr_reader` dan `attr_writer`. 89 | 90 | ```ruby 91 | class Bird 92 | attr_accessor :chirp, :fly, :spawn 93 | end 94 | 95 | Bird.instance_methods - Object.instance_methods # => [:chirp, :chirp=, :fly, :fly=, :spawn, :spawn=] 96 | ``` 97 | 98 | 99 | ## Class Variables 100 | 101 | Class variable merupakan variabel yang digunakan bersama oleh semua instance suatu kelas, mirip seperti konsep static variable di Java atau C++. Class variable di Ruby harus diawali dengan `@@`. 102 | 103 | ```ruby 104 | class Bird 105 | @@count = 0 106 | 107 | def initialize 108 | @@count += 1 109 | end 110 | 111 | def count 112 | @@count 113 | end 114 | end 115 | 116 | b1 = Bird.new 117 | b2 = Bird.new 118 | b3 = Bird.new 119 | b1.count # => 3 120 | ``` 121 | 122 | 123 | ## Class Methods 124 | 125 | Class method (static method) merupakan method yang berasosiasi dengan kelas atau module di Ruby, bukan instance dari suatu kelas. Kita bisa mengeksekusi sebuah class method tanpa sebuah instance objek. Class method di Ruby selalu diawali dengan `self.` 126 | 127 | ```ruby 128 | class Bird 129 | def self.tweet 130 | puts "Tweeeeet!!" 131 | end 132 | end 133 | 134 | Bird.tweet # => Tweeeeet!! 135 | ``` 136 | 137 | ## Inheritance 138 | 139 | Pewarisan (inheritance) pada Ruby dilakukan dengan menggunakan operator `<`. Tidak seperti C++ yang mendukung multiple inheritance, Ruby menggunakan single inheritance, yaitu sebuah kelas hanya bisa mewarisi properti dari 1 parent class. 140 | 141 | ```ruby 142 | class Bird 143 | attr_accessor :chirp, :egg 144 | end 145 | 146 | class Duck < Bird 147 | attr_accessor :quack 148 | end 149 | 150 | d = Duck.new 151 | put d.respond_to?(:egg) # => true 152 | ``` 153 | 154 | Jika kelas `Bird` di atas berada di file yang berbeda dengan kelas `Duck`, maka terlebih dulu kita perlu `require` file tersebut. Ruby akan mencari file tersebut berdasarkan `$LOAD_PATH` yang telah didefinisikan. 155 | 156 | 157 | ## Access Control 158 | 159 | Akses ke metode dan konstan pada suatu kelas di Ruby, bisa diatur dengan kata kunci berikut ini: 160 | 161 | * `public` 162 | Default, bisa diakses oleh siapa saja dari mana saja. 163 | 164 | * `private` 165 | Membatasi cakupan suatu metode hanya bisa diakses oleh objek tersebut. 166 | 167 | * `protected` 168 | Bisa diakses oleh objek dari kelas tersebut dan dari kelas-kelas turunannya. 169 | 170 | ```ruby 171 | class Dog 172 | def bark 173 | puts "Woof!" 174 | end 175 | 176 | private 177 | 178 | def walk 179 | puts "Walk!" 180 | end 181 | 182 | protected 183 | 184 | def sit 185 | puts "Sit!" 186 | end 187 | 188 | def eat 189 | puts "Eat!" 190 | end 191 | end 192 | 193 | class Chihuahua < Dog 194 | def sitdown 195 | self.sit 196 | end 197 | 198 | def run 199 | self.walk 200 | end 201 | end 202 | 203 | d = Dog.new 204 | d.bark # => 'Woof!' 205 | d.walk # => error 206 | d.sit # => error 207 | d.eat # => error 208 | 209 | c = Chihuahua.new 210 | c.bark # => 'Woof!' 211 | c.sitdown # => 'Sit!' 212 | c.run # => error 213 | ``` 214 | 215 | 216 | ## Modules 217 | 218 | Pada Ruby, modul itu mirip seperti kelas, tetapi tidak bisa di-instantiate. Sebuah kelas dapat mengandung > 1 modul. sehingga ketika kelas tersebut di-instantiate, maka semua properti dari modul-modul tersebut akan tercakup pada objek si kelas. Hal ini memungkinkan konsep yang mirip dengan multiple inheritance. Identifier pada tiap-tiap modul akan di-override oleh definisi yang terakhir. Dengan demikian, penamaan yang bertabrakan bisa dihindari. 219 | 220 | Pada Ruby, modul juga merupakan sebuah namespace. Sebuah namespace adalah sekumpulan nama (seperti nama-nama method), yang memiliki cakupan/konteks. Sebuah kelas Ruby juga bisa dianggap sebagai namespace. 221 | 222 | Penamaan modul harus diawali dengan huruf besar. Sebuah modul bisa mengandung metode, konstan, modul lain dan bahkan kelas. Sebuah modul bisa diwarisi oleh modul lain, tetapi tidak bisa diwarisi oleh sebuah kelas. 223 | 224 | ```ruby 225 | module FlyingAnimal 226 | def fly 227 | puts "Flying high.." 228 | end 229 | end 230 | 231 | module LayingAnimal 232 | def egg 233 | puts "Spawning.." 234 | end 235 | end 236 | 237 | class Bird 238 | include FlyingAnimal, LayingAnimal 239 | end 240 | 241 | b = Bird.new 242 | b.fly # => Flying high.. 243 | b.egg # => Spawning.. 244 | ``` 245 | 246 | 247 | ## Variable 248 | 249 | Di Ruby, variabel tidak perlu dideklarasikan. Ruby menggunakan "duck typing", semacam dynamic typing. Jika sebuah nilai bertingkah laku seperti tipe tertentu, misalnya integer, maka Ruby akan memberinya suatu konteks dan memberlakukannya pada kontes tersebut. If it walks like a duck, quacks like a duck, flies like a duck, and swims like a duck (or integer or float, etc.), then it is probably a duck. 250 | 251 | Sekilas ulasan kembali beberapa jenis variable di Ruby. 252 | 253 | ### Local Variable 254 | 255 | Variabel lokal memiliki cakupan yang lokal juga sesuai konteksnya, misalnya di dalam suatu metode atau perulangan. Variabel lokal pada Ruby hanya boleh diawali dengan huruf kecil atau underscore (_). 256 | 257 | ```ruby 258 | class Foo 259 | def self.bar 260 | Foobar = 1 # error 261 | _foobar = 2 262 | puts _foobar 263 | end 264 | end 265 | ``` 266 | 267 | ### Instance Variable 268 | 269 | Instance variable hanya bisa diakses dari luar suatu objek melalui accessor method. Instance variable selalu diawali dengan tanda `@`. 270 | 271 | 272 | ### Class Variable 273 | 274 | Class variable merupakan variabel yang digunakan bersama oleh semua instance suatu kelas, mirip seperti konsep static variable di Java atau C++. Class variable di Ruby selalu diawali dengan `@@`. 275 | 276 | 277 | ### Global Variables 278 | 279 | Global variable bisa diakses dari mana saja. Di Ruby, global variable harus diawali dengan tanda `$`. 280 | 281 | 282 | ### Constants 283 | 284 | Variabel konstan di Ruby harus diawali dengan huruf besar, dan biasanya (secara konvensi) nama sebuah konstan ditulis dengan huruf besar semua. 285 | -------------------------------------------------------------------------------- /Session3.md: -------------------------------------------------------------------------------- 1 | # Session 3: Advanced Topic 2 | 3 | ## Exceptions 4 | 5 | Exception terjadi ketika aliran program terinterupsi karena error. Penanganan exception pada Ruby mirip dengan C++ dan Java. 6 | 7 | | C++ | Java | Ruby | 8 | |:----------:|:-----------:|:------------:| 9 | | try {} | try{} | begin/end | 10 | | catch {} | catch {} | rescue | 11 | | | finally | ensure | 12 | | throw | throw | raise | 13 | 14 | 15 | Ketika terjadi error, baris selanjutnya tidak akan dieksekusi. Ruby akan menangkap error tersebut dengan `rescue`, dan akhirnya menjalankan instruksi `ensure`. 16 | 17 | ```ruby 18 | def foo 19 | str = "Hello world" 20 | str.bar 21 | puts "This line is ignored" 22 | rescue NoMethodError => e 23 | print "Catching: " + e.to_s 24 | rescue Exception 25 | print "Problem found!" 26 | ensure 27 | puts " -- This is it" 28 | end 29 | 30 | foo # => Catching: undefined method `bar' for "Hello world":String -- This is it 31 | ``` 32 | 33 | Kita bisa melemparkan exception kapan saja dengan `raise`. 34 | 35 | ```ruby 36 | def goo(n) 37 | if n < 0 38 | raise StandardError, "Negative number" 39 | else 40 | puts "It's positive" 41 | end 42 | end 43 | 44 | def hoo 45 | goo(-1) 46 | puts "It is printed?" 47 | rescue Exception => e 48 | print "Exception: " + e.to_s 49 | end 50 | 51 | hoo # => Exception: Negative number 52 | ``` 53 | 54 | Selain menggunakan keyword `rescue` dan `raise`, kita bisa juga menggunakan method `catch` 55 | dan `throw` pada Ruby. Penggunaan argumen `catch` dan `throw` pada Ruby ini berbeda 56 | dengan di Java, meskipun namanya sama. 57 | 58 | ```ruby 59 | def print_me(n) 60 | puts n 61 | throw :done if n <= 0 62 | print_me(n-1) 63 | end 64 | 65 | catch(:done) do 66 | print_me(5) 67 | end 68 | ``` 69 | 70 | Penggunaan `throw` dan `catch` di ruby sangat jarang dilakukan dan sebaiknya dihindari 71 | 72 | ## Advanced Blocks 73 | 74 | ### Implicit Block 75 | 76 | Setiap method di ruby dapat menerima block sebagai argumen terakhir, sekalipun dalam definisi method tersebut 77 | tidak mencantumkan argumen block. 78 | 79 | Untuk mengecek apakah terdapat sebuah argumen block, panggil `block_given?` dalam sebuah method. 80 | Sedangkan untuk mengeksekusi block tersebut dapat menggunakan `yield`. 81 | 82 | ```ruby 83 | def foo 84 | if block_given? 85 | yield 86 | yield 87 | else 88 | puts 'No block here' 89 | end 90 | end 91 | 92 | foo { print 'Hello ' } # => Hello Hello 93 | 94 | foo # => No block here 95 | ``` 96 | 97 | `yield` dapat menerima argumen yang akan diteruskan ke block yang dieksekusi 98 | 99 | ```ruby 100 | def foo 101 | yield([1,2,3]) 102 | end 103 | 104 | foo do |array| 105 | puts array 106 | end 107 | ``` 108 | 109 | ### Proc 110 | 111 | Ruby memungkinkan kita menyimpan *procedure* atau `Proc` sebagai objek lengkap dengan konteksnya. 112 | 113 | Penggunaan *block* pada Ruby itu relatif sederhana. Meskipun demikian, 114 | kita mungkin perlu punya beberapa *block* yang berbeda dan menggunakannya berkali-kali. 115 | Untuk menghindari kode yang repetitif tersebut, kita bisa menyimpannya sebagai *procedure* 116 | atau `Proc`, sebagai objek yang lengkap dengan konteksnya. Perbedaan antara *block* dan 117 | `Proc` adalah *block* merupakan suatu `Proc` yang tidak bisa disimpan dan merupakan solusi sekali pakai. 118 | 119 | ```ruby 120 | def foo 121 | label = proc do 122 | print "counting" 123 | end 124 | 125 | count = Proc.new do 126 | [1,2,3,4,5].each do |i| 127 | print i 128 | end 129 | puts 130 | end 131 | 132 | label.call 133 | print " - " 134 | count.call 135 | end 136 | 137 | foo # => counting - 12345 138 | ``` 139 | 140 | 141 | ### Lambda 142 | 143 | Di Ruby, *lambda* merupakan suatu *method* yang menciptakan objek *Proc* yang terkait dengan konteks saat ini 144 | dan melakukan pengecekan parameter ketika dipanggil. 145 | 146 | Berbeda dengan Proc, lambda akan mengecek jumlah argumen yang dioper. 147 | 148 | ```ruby 149 | def foo(code) 150 | one, two = 1, 2 151 | code.call(one, two) 152 | end 153 | 154 | foo(Proc.new { |a, b, c| puts "a = #{a}, b = #{b}, c = #{c.class}" } ) # => a = 1, b = 2, c = NilClass 155 | 156 | foo(lambda { |a, b, c| puts "a = #{a}, b = #{b}, c = #{c.class}" } ) # => ArgumentError: wrong number of arguments (2 for 3) 157 | ``` 158 | ### Passing Proc Around 159 | 160 | Untuk mem-pass suatu proc atau lambda sebagai argumen suatu method, variabel proc/lambda tersebut diberi prefix `&` 161 | 162 | ```ruby 163 | print_item = proc do |item| 164 | puts item 165 | end 166 | 167 | [1,2,3].each &print_item 168 | ``` 169 | 170 | 171 | ## Classes as Objects 172 | 173 | *Object* merupakan *root* dari hierarki kelas di Ruby. Semua *method* dari kelas *Object* akan tersedia 174 | di seluruh kelas kecuali di-*override* secara eksplisit. Selengkapnya ada di http://www.ruby-doc.org/core/classes/Object.html 175 | 176 | 177 | ## Metaprogramming 178 | 179 | *Metaprogramming* merupakan pemrograman yang memanipulasi program lainnya atau bahkan dirinya sendiri, 180 | atau mengerjakan hal-hal yang biasanya dilakukan pada *compile time*, pada waktu *runtime*. 181 | Kemampuan suatu objek untuk memanipulasi dirinya sendiri ini sering disebut sebagai *reflection*. 182 | 183 | Metaprogramming di ruby memanfaatkan sifat ruby yang sangat dinamis. Beberapa teknik yang sering digunakan 184 | dalam metaprogramming di ruby antara lain: 185 | 186 | ### Monkey Patching 187 | 188 | Salah satu bentuk *metaprogramming* adalah *monkey patching*, yaitu memodifikasi *runtime code* dari suatu 189 | bahasa yang dinamis tanpa mengubah *source code* aslinya. 190 | 191 | Contoh yang sangat menarik dalam monkey patching di ruby adalah dengan melakukan overwrite kelas yang 192 | sudah didefinisikan sebelumnya, termasuk kelas yang built-in (bawaan) ruby seperti `Fixnum`. 193 | Kelas dalam ruby dapat dibuka dan didefinisikan ulang kapanpun kita mau. Dengan demikian kita dapat 194 | dengan mudah mengubah behaviour dari suatu object sesuai keinginan kita. 195 | 196 | Dibawah ini adalah contoh monkey patching yang sangat berbahaya. Di sini kita membuka kembali kelas `Fixnum` 197 | yang merupakan kelas bagi angka integer bawaan ruby. Kemudian kita mendefinisikan ulang method `+` untuk 198 | selalu me-return angka 42 kapanpun. 199 | 200 | ```ruby 201 | class Fixnum 202 | def +(x) 203 | 42 204 | end 205 | end 206 | 207 | 3 + 4 # => 42 208 | ``` 209 | 210 | Kita bahkan juga bisa meng-*override* semua objek dengan cara meng-override kelas `Object` yang merupakan 211 | hirarki kelas tertinggi, sehingga semua objek akan terpengaruh. 212 | 213 | Contoh berikut ini menambahkan atribut timestamp bagi semua object, sehingga setiap object akan menyimpan 214 | waktu ketika object tersebut diinisiasi. 215 | 216 | ```ruby 217 | class Object 218 | attr_accessor :timestamp 219 | end 220 | 221 | class Class 222 | alias_method :old_new, :new 223 | def new(*args) 224 | result = old_new(*args) 225 | result.timestamp = Time.now 226 | result 227 | end 228 | end 229 | 230 | class Foo 231 | end 232 | 233 | Foo.new.timestamp 234 | ``` 235 | 236 | ### method_missing 237 | 238 | Ketika kita mengirimkan pesan ke objek, objek akan mengeksekusi *method* pertama yang ditemukannya pada 239 | *method lookup path* dengan nama yang sama persis dengan pesan. Jika tidak ditemukan, 240 | ia akan melemparkan *exception* NoMethodError, kecuali kalau kita sudah menyediakan sebuah *method* bernama `method_missing`. 241 | 242 | `method_nissing` dapat kita override sesuai dengan keinginan kita. Misalnya kita dapat meng-override `method_missing` 243 | sehingga jika kita memanggil method yang tidak tersedia, object tersebut akan memberi kita peringatan. 244 | 245 | ```ruby 246 | class Foo 247 | def method_missing(m, *args, &block) 248 | puts "method #{m} is not defined. Please define it first." 249 | end 250 | end 251 | 252 | Foo.new.bar # => method bar is not defined. Please define it first. 253 | ``` 254 | 255 | ## I/O 256 | 257 | Dasar dari semua input/output di Ruby adalah kelas `IO`, di mana merepresentasikan stream input/output data dalam bentuk byte. Standard stream mencakup stdin (keyboard), stdout (display ke layar) dan stderr (error output). Parameter pertama konstruktor kelas IO adalah nomer *file descriptor*, sedangkan parameter keduanya merupakan mode I/O. Ada beberapa macam mode I/O, antara lain: r, r+, w, w+, a, a+, b 258 | 259 | | Stream | File Descriptor | 260 | |:-----------:|:---------------:| 261 | | stdin | 0 | 262 | | stdout | 1 | 263 | | stderr | 2 | 264 | 265 | ```ruby 266 | ios = IO.new( 1, "w" ) 267 | ios.puts "Hello IO" # => Hello IO 268 | 269 | ios.fileno # => 1 270 | ios.to_i # => 1 271 | 272 | ios.close 273 | ``` 274 | 275 | ## Files 276 | 277 | Di Ruby, kita bisa memanipulasi file dan folder dengan menggunakan *method-method* dari kelas Dir dan File. 278 | 279 | Buat dan hapus folder: 280 | 281 | ```ruby 282 | Dir.mkdir("/tmp/ruby_basic",777) 283 | dir = Dir.pwd 284 | puts dir 285 | Dir.rmdir("/tmp/ruby_basic") 286 | ``` 287 | 288 | Buat dan hapus file: 289 | 290 | ```ruby 291 | file = File.new( "aaaa.txt", "w" ) 292 | File.rename( "aaaa.txt", "bbbb.txt" ) 293 | File.delete( "bbbb.txt" ) 294 | ``` 295 | 296 | Pemrosesan file per baris pada Ruby: 297 | 298 | ```ruby 299 | file = File.open( "Readme.md" ) if File::exists?( "Readme.md" ) 300 | 301 | file.each do |line| 302 | print "#{file.lineno}. ", line 303 | end unless file.closed? 304 | 305 | file.close 306 | ``` 307 | -------------------------------------------------------------------------------- /Session4.md: -------------------------------------------------------------------------------- 1 | # Session 4: Libraries & Testing 2 | 3 | ## Libraries 4 | 5 | Salah satu keunggulan ruby adalah ruby memiliki banyak sekali library 6 | yang bisa kita pakai sesuai kebutuhan kita. 7 | Standar distribusi library di ruby adalah dengan menggunakan format yang 8 | bernama *gem*. 9 | 10 | ### Instalasi & menggunakan gems 11 | 12 | Sebuah gem adalah suatu kumpulan file library beserta metadatanya yang 13 | dikompresi dengan gzip, biasanya dengan ekstensi `.gem`. 14 | Untuk menginstall suatu library menggunakan gem, kita menggunakan 15 | perintah 16 | 17 | ``` 18 | $ gem install 19 | ``` 20 | 21 | contoh, kita akan menginstall builder, library untuk membuat dokumen xml: 22 | 23 | ``` 24 | $ gem install builder 25 | ``` 26 | 27 | Untuk menggunakan library, baik yang bawaan ruby maupun yang diinstall 28 | menggunakan gem, kita menggunakan method `require ""`. 29 | 30 | ```ruby 31 | require "rubygems" # tidak dibutuhkan untuk ruby 1.9 ke atas 32 | require "builder" 33 | 34 | xml = Builder::XmlMarkup.new 35 | xml.person do 36 | xml.name "Slamet Riyadi" 37 | xml.location "Indonesia" 38 | end 39 | ``` 40 | 41 | ### Bundler 42 | 43 | Untuk memanage library-library yang digunakan pada suatu project, kita dapat 44 | menggunakan bundler. 45 | 46 | Pada root directory suatu project, kita mencatat semua library yang kita gunakan 47 | beserta versi masing-masing pada file dengan nama *Gemfile*. 48 | 49 | ``` 50 | mkdir my_project 51 | cd my_project 52 | touch Gemfile 53 | ``` 54 | 55 | ```ruby 56 | # Gemfile 57 | source 'http://rubygems.org' 58 | 59 | gem 'rails', '3.2.3' 60 | gem "authlogic" 61 | gem 'will_paginate', :git => "git://github.com/bukalapak/will_paginate.git" 62 | gem "simple_form", "~> 2.0" 63 | gem "whenever", :require => false 64 | ``` 65 | 66 | Untuk menginstall library yang dibutuhkan, kita menggunakan perintah `bundle install`. 67 | Bundler kemudian akan membuat file dengan nama *Gemfile.lock* yang mencatat versi 68 | library yang digunakan saat ini, sehingga ketika kita menjalankan `bundle install` 69 | pada lain waktu, kita akan mendapatkan library dengan versi yang sama. 70 | 71 | Kemudian pada project kita, kita me-load library menggunakan bundler sebagai berikut: 72 | 73 | ```ruby 74 | require "rubygems" 75 | require "bundler/setup" 76 | 77 | require "authlogic" 78 | ``` 79 | 80 | ### Packaging Programs and Libraries for Distribution 81 | 82 | Untuk membuat kode kita menjadi gem, kita akan menggunakan bundler untuk menyiapkan 83 | package dan strukturnya, sebagai berikut: 84 | 85 | ``` 86 | bundle gem namagem 87 | ``` 88 | 89 | yang akan menghasilkan struktur direktori di mana kita bisa meletakkan file-file library kita. 90 | Kemudian kita edit file namagem.gemspec dengan data yang sesuai: 91 | 92 | ```ruby 93 | # -*- encoding: utf-8 -*- 94 | $:.push File.expand_path("../lib", __FILE__) 95 | require "namagem/version" 96 | 97 | Gem::Specification.new do |s| 98 | s.name = "namagem" 99 | s.version = Namagem::VERSION 100 | s.platform = Gem::Platform::RUBY 101 | s.authors = ["Nugroho Herucahyono"] 102 | s.email = ["xinuc@xinuc.org"] 103 | s.homepage = "" 104 | s.summary = %q{Gem tanpa fitur} 105 | s.description = %q{Gem tanpa fitur.} 106 | 107 | s.add_development_dependency "rspec" 108 | 109 | s.rubyforge_project = "namagem" 110 | 111 | s.files = `git ls-files`.split("\n") 112 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 113 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 114 | s.require_paths = ["lib"] 115 | end 116 | ``` 117 | 118 | Selanjutnya kita dapat melakukan build gem tersebut. 119 | 120 | ``` 121 | gem build namagem.gemspec 122 | ``` 123 | 124 | Pada umumnya, library ruby opensource dipublish oleh penulisnya ke rubygems.org, 125 | sehingga siapapun dapat menginstall dan menggunakannya dengan mudah. 126 | Kita dapat mempublish gem kita dengan perintah sebagai berikut: 127 | 128 | ``` 129 | gem push namagem-0.0.1.gem 130 | ``` 131 | 132 | ## Testing 133 | 134 | Testing merupakan aspek yang sangat penting dalam programming. Testing dapat 135 | digunakan untuk memastikan apakah kode yang kita tulis bekerja sesuai dengan 136 | yang kita harapkan. 137 | 138 | Di ruby, ada banyak sekali testing framework yang tersedia. 139 | Diantaranya: test-unit, minitest, rspec, shoulda dan lain-lain. 140 | Pada sesi ini, kita akan membahas unit testing dengan menggunakan minitest, 141 | yang merupakan test framework bawaan ruby (>= 1.9). 142 | 143 | ### Unit Testing with Minitest 144 | 145 | Untuk menggunakan minitest, kita cukup me-require library tersebut dengan 146 | `require 'minitest/autorun'` dan membuat testcase untuk mengetes kode yang 147 | kita buat dengan assertion. 148 | 149 | ```ruby 150 | # person.rb 151 | class Person 152 | def initialize(first_name, last_name) 153 | @first_name = first_name 154 | @last_name = last_name 155 | end 156 | 157 | def fullname 158 | @first_name + " " + @last_name 159 | end 160 | end 161 | ``` 162 | 163 | ```ruby 164 | # person_test.rb 165 | require './person' 166 | require 'minitest/autorun' 167 | 168 | class PersonTest < MiniTest::Unit::TestCase 169 | def setup 170 | @person = Person.new "John", "Smith" 171 | end 172 | 173 | def test_create_a_correct_fullname 174 | assert_equal "John Smith", @person.fullname 175 | end 176 | end 177 | ``` 178 | 179 | atau kita dapat menuliskan test dengan gaya rspec: 180 | 181 | ```ruby 182 | # person_test.rb 183 | require './person' 184 | require 'minitest/autorun' 185 | 186 | describe Person do 187 | before do 188 | @person = Person.new "John", "Smith" 189 | end 190 | 191 | it "should create a correct fullname" do 192 | @person.fullname.must_equal "John Smith" 193 | end 194 | end 195 | ``` 196 | 197 | kemudian kita jalankan dengan `ruby person_test.rb`, yang akan 198 | menghasilkan 199 | 200 | ``` 201 | Run options: --seed 6446 202 | 203 | # Running tests: 204 | 205 | . 206 | 207 | Finished tests in 0.000741s, 1349.7900 tests/s, 1349.7900 assertions/s. 208 | 209 | 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips 210 | ``` 211 | 212 | yang berarti bahwa ada 1 test yang dijalankan tanpa failure. 213 | 214 | ### Introduction to TDD 215 | 216 | TDD (test driven development) adalah metode pembuatan software dengan menuliskan test 217 | terlebih dahulu, baru kemudian menulis kode implementasinya. Setelah kode implementasi 218 | memenuhi testnya, kode kemudian di refactor ke dalam bentuk yang lebih modular. 219 | 220 | Misalnya kita akan menulis kode untuk mengubah besaran temperatur dari celsius ke fahrenheit 221 | dan sebaliknya. Pertama, kita akan membuat list fitur dari kode tersebut, yaitu: 222 | 223 | * dapat mengubah temperatur dari celsius ke fahrenheit 224 | * dapat mengubah temperatur dari fahrenheit ke celsius 225 | 226 | kemudian, kita buat test case nya terlebih dahulu, sebagai berikut: 227 | 228 | ```ruby 229 | # temperature_converter_test.rb 230 | 231 | require 'minitest/autorun' 232 | 233 | describe TemperatureConverter do 234 | it "can convert temperature from celsius to fahrenheit" do 235 | TemperatureConverter.new(10).celsius_to_fahrenheit.must_equal 50 236 | end 237 | 238 | it "can convert temperature from fahrenheit to celsius" do 239 | TemperatureConverter.new(50).fahrenheit_to_celsius.must_equal 10 240 | end 241 | end 242 | ``` 243 | 244 | Jika kita jalankan test ini, maka tentu akan gagal. Baru kemudian kita buat implementasinya 245 | sampai testnya berhasil. 246 | 247 | ```ruby 248 | # temperature_converter.rb 249 | 250 | class TemperatureConverter 251 | def initialize(temp) 252 | @temp = temp 253 | end 254 | 255 | def celsius_to_fahrenheit 256 | @temp * 9 / 5 + 32 257 | end 258 | 259 | def fahrenheit_to_celsius 260 | (@temp - 32) * 5 / 9 261 | end 262 | end 263 | ``` 264 | --------------------------------------------------------------------------------