Ruby-pikaopas

Paula Kemppi, Juuso Montonen, Martin Pärtel

(26.04.2007)

Sisältö

  1. Johdanto
  2. Perusteet
  3. Luokat ja oliot
  4. Moduulit
  5. Sekalaista
  6. Linkkejä

Johdanto

Ruby on 1995 julkaistu reflektiivinen, dynaaminen, tulkittu olio-ohjelmointikieli.

Työtoverin "syntymäkiven" mukaan nimetyn ohjelmointikielen on kehittänyt Yukihiro "Matz" Matsumoto, joka aloitti Rubyn kehityksen 1993.

Rubyn ensimmäinen versio julkistettiin 1995 ja tällä hetkellä virallinen painos on 1.8.6. Yukihiro Matsumoton mukaan 2007 joulukuussa julkaistavan Ruby 2.0:n olennaisimpia muutoksia on Rubyn suoritusympäristön siirtäminen YARV- virtuaalikoneeseen. Tämän muutoksen tarkoitus on parantaa Rubyn suorituskykyä, joka tulkituissa kielissä on käännettyjä heikompi.

Ohjelmointikielen kehittäjän mukaan tärkein periaate Rubyn kehittämisessä on fokuksen siirtäminen pois laitetasosta inhimilliselle tasolle, eli asettaa järjestelmän käyttäjän tarpeet ensisijalle. Ruby on kehitetty ohjelmoijan tuottavuutta ja ohjelmoinnin hauskuutta silmällä pitäen. Sääli, ettei tulkki kerro puujalkavitsejä kohdatessaan virheen.

Rubya kutsutaan monen paradigman ohjelmointikieleksi, koska se mahdollistaa proseduraalisen, oliopohjaisen sekä funktionaalisen ohjelmoinnin. Lisäksi Rubystä löytyy tuki introspektiolle, reflektiolle ja metaohjelmoinnille. Ruby on siis hyvin monipuolinen ohjelmointikieli, joka soveltuu skriptaamisesta web-palveluiden rakentamiseen ja kaikkeen mahdolliseen mihin perinteiset olio-ohjelmointikielet kelpaa. Rubyn web-palveluiden kehitysympäristö tunnetaan erikseen nimellä Ruby on Rails.

Rubyn ominaisuudet lyhyesti ja sekavasti

Huonot puolet

Valitettavasti Rubyssa ei ole täyttä Unicode-tukea, vaikka siinä on osittainen tuki UTF-8:lle. Toinen puute on Rubyn käännettäviä kieliä heikompi suorituskyky. Tämän ongelman korjaamiseksi Rubyn suoritus siirtyy seuraavissa versioissa virtuaalikoneympäristöön, jonka pitäisi nopeuttaa ohjelmien suoritusta. Käsityksen Rubyn suoritustehokkuudesta saa tästä vertailusta C:n (gcc:llä) ja Rubyn välillä. Tässä myös kiinnostava kaavio Javan ja Rubyn eroista.

Perusteet

Komennot

Ruby-tiedostojen pääte on tavallisesti .rb. Valmiita Ruby-ohjelmia suoritetaan komennolla ruby <tiedosto>.rb. Kielen opettelemiseen ja kokeilemiseen kannattaa käyttää irb -komentotulkkia. Dokumentaatiota voi selata ri-komennolla, esimerkiksi: ri Array#sort.

Nimet

Paikalliset muuttujat täytyy aloittaa pienellä, luokat ja vakiot isolla alkukirjaimella (i, Alkuelain, MALLI). Olion jäsenmuuttujat alkavat @-merkillä (@x). Luokkamuuttujien etuliite on @@ (@@count). Globaalien eteen kirjoitetaan $ ($stdout).

Lisäksi on tapana päättää kysyvät metodit kysymysmerkkiin (empty?) ja vaaralliset, olion tilaa muuttavat metodit huutomerkkiin (sort!).

Perusrakenteet

Lauseet

# Kommentit alkavat risuaidalla

# Yksi lause / rivi
x = 3

# Lauseet voi myös erottaa puolipisteellä
y = x + 1; z = y * 3

# Laskujärjestys on intuitiivinen
z = 1 + 2 * 3

# Lausetta voi jatkaa seuraavalle riville kenoviivalla
x = 1 + \
    2 + \
    3

# Perustulostus
print "Ruby on kivaa!\n"
puts "Kivaa!"  # autom. rivinvahito
puts 123.to_s  # to_s-metodi muuttaa luvun merkkijonoksi
p 123          # funktio p tulostaa minkä tahansa tietotyypin jollain tavalla
               # (vrt. Javan System.out.println(Object))

Ehtolauseet

# Perus ehtolause
if x > 0
    puts "Hello World"
elsif x == 0 or x == -1
    puts "bla"
else
    puts ":("
end

# If-lauseen voi kirjoittaa yhdelle riville joko then-avainsanalla...
if x > 0 then puts "Hello World" end

# ... tai Perlistä tutulla <lause> if <ehto> -rakenteella
puts "w00t" if x >= 2
y = 14 unless x != 3

Toistolauseet

while x < 10
    # (...)
end

# Alkuehtoinen toisto yhdellä rivillä
x -= 1 while x > 0
x += 1 until x == 10

Loppuehtoinen toisto kirjoitetaan begin – end -lohkojen avulla:

begin
  # Suoritetaan ainakin kerran
end while x > 0

Tavallinen for-silmukka näyttää tältä:

for i in 1..3
  # Toistuu kolmesti
end
for i in 1...3
  # Toistuu kahdesti; 3 jää pois
end

Taulukot ja assosiaatiotaulut

Rubyn taulukot ovat heterogeenisia, eli ne voivat sisältää mitä tahansa arvoja ilman rajoituksia. Taulukoiden indeksointi alkaa nollasta, mutta niitä voi myös indeksoida negatiivisella luvulla, jolloin alkion paikka lasketaan lopusta alkaen.

a = []  # Tyhjä taulukko
a = [0, 1, 2, 3]
a = [nil, 1, [2], "viimeinen"]
a[3]  # => "viimeinen"
a[-1] # => "viimeinen"

Assosiaatiotaulu (hash) on joukko avain/arvo -pareja. Sillä ei ole järjestystä.

h = {}  # Tyhjä hash-taulu
h = {"a" => 1, "b" => 2, "c" => 3}
h = {0 => [], "nolla" => {}, nil => 42}
h[0]  # => []
h[nil]  # => 42

Kuten kaikki muutkin Rubyn arvot, myös taulukot ja assosiaatiotaulut ovat olioita, ja niillä on suuri joukko metodeja. Metodeista saa helposti luettelon kirjoittamalla irb-tulkkiin:

[].methods.sort
{}.methods.sort

Rubyssa ei ole erillistä monikkotietotyyppiä (tuple). Monikkojen sijaan käytetään taulukkoja.

Taulukot voidaan kirjoittaa sijoituslauseisiin ilman hakasulkuja. Näin saadaan muiden kielien monikkoja muistuttava muoto: a = 1, 2, 3 (arvoja ei saa ympäröidä tavallisilla suluilla). Taulukon elementit evaluoidaan vasemmalta oikealle.

Ruby tukee myös yhtäaikaista sijoitusta useaan muuttujaan: a, b = 1, 2 (vasemmalla puolella saa myös käyttää sulkuja). Näin saadaan aikaan monesta kielestä tuttu tapa vaihtaa kahden muuttujan arvot keskenään: a, b = b, a

Seuraavat lauseet tarkoittavat samaa:

a, b = b, a
a, b = [b, a]
(a, b) = b, a
(a, b) = [b, a]

Symbolit

Symbolit ovat nopeita merkkijonoavaimia. Niitä käytetään mm. samanlaisissa tilanteissa kuin C:n tai Javan enum-arvoja. Luokkien yhteydessä nähdään, miten symboleilla voi kätevästi nimetä jäsenmetodeja ja -muuttujia kielen reflektiivisiä ominaisuuksia käytettäessä.

Symbolien etuliitteenä on kaksoispiste, ja niille pätevät jotakuinkin samat rajoitukset kuin muuttujien nimille. Esim. :sym, :wtf?, :$abc123 ovat kelvollisia symboleja.

Funktiot (metodit)

Funktion määrittelyssä ja kutsussa voidaan jättää sulut pois, jos parametreja on enintään yksi. Vanhoissa Ruby-versioissa sulut sai jättää pois, vaikka parametreja oli enemmänkin, mutta tämä aiheutti liikaa epäselvyyksiä ja käytännöstä ollaan luopumassa.

Jos funktiossa ei ole erillistä return-avainsanaa, se palauttaa funktion viimeisen lauseen arvon. Rubyssa kaikki lauseet palauttavat jonkin arvon.

def toiseen x
  puts "Korotan nyt #{x} toiseen"
  x**2  # Viimeisen lauseen arvo palautetaan ilman returniakin
end

toiseen 3           # => 9
toiseen toiseen(3)  # => 81
toiseen(toiseen 3)  # => 81 ja varoitus sulutuksesta
toiseen toiseen 3   # => 81 ja varoitus sulutuksesta


# Palauttaa toisen asteen yhtälön a(x^2) + bx + c = 0 juurien joukon
def tay(a, b, c)
  raise Exception.new("Ei a saa olla nolla!") if a == 0

  d = b**2 - 4*a*c
  if d < 0 then return []
  elsif d == 0 then return [-b/(2*a)]
  else return [(-b + Math.sqrt(d))/(2*a), (-b - Math.sqrt(d))/(2*a)]
  end
end

tay(1, 2, 3)  # => nil
tay(1, 2, 0)  # => [0, -2]
tay(1, 0, 0)  # => [0]

Funktion voi määritellä ottamaan vaihtelevan määrän parametreja

def summa(*argumentit)
  summa = 0
  for i in argumentit
    summa += i
  end
  return summa
end
puts summa(1, 2, 3)  # => 6

Säännölliset lausekkeet

Rubystä löytyy työkalut säännöllisten lausekkeiden monipuoliseen rakentamiseen, joten tässä kohdassa esittelemme vain perusteet. Näiden lisäksi on saatavilla erillisiä regexp-kirjastoja esimerkiksi Oniguruma. Kuten muutkin Rubyn palikat, säännölliset lausekkeet ovat olioita (regexp-luokan ilmentymiä). Säännöllinen lauseke luodaan kutsumalla regexp-luokan konstruktoria tai käyttämällä merkintöjä /hahmo/ ja %r\hahmo\ . Rubyn säännöllisten lausekkeiden syntaksi on Perlin kaltainen, joillakin pienillä eroilla. Lisätietoa ja tarkennuksia Rubyn säännöllisten lausekkeiden käytöstä löytyy parhaiten teoksesta "Programming Ruby, The Pragmatic Programmer's Guide" kappaleesta "Standard types" (kts. linkit oppaan lopussa). Ruby ymmärtää säännöllisiä lausekkeita pääpiirteittäin seuraavanlaisella syntaksilla:

# []    alueen määrittely, [a-z] merkitsee kirjainta a:sta z:taan väliltä.
# \w    kirjain tai luku, sama kuin [0-9A-Za-z]
# \W    ei kirjain eikä luku, eli \w:n negaatio 
# \s    välilyönti merkki, sama kuin [ \t\n\r\f]
# \S    \s:n negaatio, eli mikä tahansa muu merkki kuin välilyönti
# \d    Lukumerkki, merkitsee lukua väliltä [0-9]
# \D    \d:n negaatio, eli mikä tahansa muu kuin numeroarvo välitä [0-9]
# \b    "backspace" (0x08) 
# \b    sanan raja (jos se ei ole alueen määrittelyssä)
# \B    "ei-sanan" raja, \b:n negaatio.

# =~    Hahmontunnistus operaattori, etsii annetun merkkijonon paikan.
#       Jos se ei löydy, palauttaa 'nil' arvon. 
# !~    =~ merkin negaatio, eli jos merkkijonoa ei löydy palauttaa true
# .     mikä tahansa 1 merkki paitsi uusi rivi.
# *     0 tai useampi kerta
# ?     1 tai 0 kerta
# +     1 tai useampi kerta
# ^     rivinalku tai hahmon sisällä negaatio esim. [^\d] on merkki joka ei ole luku.
# |     tai, \d|[a-b], lukumerkki tai a- tai b-kirjain
# ()    merkintöjen ryhmittely
# /     escape-merkki

# Esimerkkejä:

"abcdef" =~ /d/ # => 3 ,koska d on merkkijonon indeksissä 3.

"aaaaaa" =~ /d/ # => nil ,koska merkkiä 'd' ei löydy.

# Metodi heksaluvun etsimiseksi <> -sulkeiden sisältä.
# Palauttaa true, jos heksaluku löytyy.
def hex(x)
    (x =~ /<0(x|X)(\d|[a-f]|[A-F])+>/) != nil
end 

hex "onkos täällä heksaluku? <0xananasakäämä>"  # => false
hex "wtf? <0x800CCC097D>"  # => true

# Korottaa kaikki merkkijonossa esiintyvät numerot toiseen
"11 12 böö 13 14 foo15bar".gsub /\d+/ do |numero|
  numero.to_i * 2
end  # => "22 24 böö 26 28 foo30bar"

Säännöllisten lauseiden koko syntaksi on listattu tiiviisti Ruby QuickRef-sivustolla.

Lohkot (sulkeumat)

Lohkot (blocks) ovat sulkeumia, eli nimettömiä funktioita, jotka säilyttävät viittausympäristönsä muuttujat. Lohko voidaan määritellä joko aaltosulkujen { } avulla tai do – end -rakenteella. Mitä tahansa metodia voidaan kutsua antamalla sille lohko parametrina. Lohko kirjoitetaan aina jonkin metodikutsun yhteyteen. Metodi voi kutsua parametrina saamaansa lohkoa yield-avainsanalla.

# foo on funktio, joka käyttää saamaansa lohkoa
def foo
  yield 10, 20 # kutsutaan lohkoa parametreilla 10 ja 20
end

# kutsutaan foo:ta kaksiparametrisella lohkolla
foo {|x, y|
  puts 7*x + y
}  # => 90

# metodi foo olisi voitu kirjoittaa myös näin:
def foo2(&block)
  block.call(10, 20)
end

# seuraava metodi kutsuu lohkoaan kolme kertaa
def kolmeKertaa
  yield
  yield
  yield
end

# Parametriton lohko do-syntaksilla
kolmeKertaa do
  puts "Heippa"
end

# Sama voitaisiin muuten kirjoittaa näinkin
3.times do
  puts "Heippa"
end

Lohkojen yleisin käyttötapa on erilaisten iteraattorien ja generaattorien määrittäminen. Kokoelmat, kuten listat ja assosiaatiotaulut sisältävät mm. each-metodin, joka kutsuu lohkoa vuorotellen kaikilla kokoelman alkioilla. for-silmukka on itse asiassa vain vaihtoehtoinen kirjoitustapa each-metodin kutsumiselle.

[1, 2, 3].each do |i|
  puts i
end
for i in [1, 2, 3]
  puts i
end

Lohko voi käyttää viittausympäristönsä paikallisia muuttujia. Lohko viittausympäristöneen voidaan tallettaa Proc-olioon myöhempää käyttöä varten. Muuttujat säilyvät sulkeumassa vaikka lohkon luoneen metodin suoritus päättyy.

# lohko voi käyttää paikallista muuttujaa
def suuret(joukko)
  keskiarvo = 165
  return joukko.select {|e| e.koko > keskiarvo }
end

# luodaan sulkeuma-olio, joka käyttää metodin tee_kertoja parametria
def tee_kertoja(kerroin)
  return Proc.new {|x| kerroin*x }
end
kertoja = tee_kertoja(4)
kertoja.call(2)  # => 8
[1, 2, 3].map {|x| kertoja.call(x) }  # => [4, 8, 12]

Lohkot ovat yksi Rubyn keskeisimpiä ominaisuuksia, ja niitä käytetään joskus yllättävilläkin tavoilla.

# avaa tiedoston, suorittaa sulkeuman ja sulkee tiedoston (vaikka tulisi poikkeus)
File.open(filename) {|f| doSomethingWithFile(f)}

require 'cgi'

cgi = CGI.new("html4")
# Määrittää html-sivun
cgi.out {
  cgi.html {
    cgi.head { cgi.title{"Ruby CGI esimerkki"} } +
    cgi.body {
      cgi.h1 { "Hello World!" } +
      cgi.p { cgi.b { "Ruby on kivaa!" } }
    }
  }
}

Luokat ja oliot

Rubyssa kaikki muuttujaan sijoitettavat arvot ovat olioita, ja kaikilla olioilla on viitesemantiikka lukuun ottamatta pieniä kokonaislukuja (Fixnum-luokka), totuusarvoja (true/false) ja tyhjää arvoa (nil). Näitä poikkeustapauksia nimitetään "välittömiksi arvoiksi" (immediate value); esimerkiksi kokonaislukua 1 vastaa aina sama olioilmentymä.

Esimerkki luokan määrittelystä

class Yliluokka
  def yliluokan_metodi(x)
    x + 1
  end
end

class Luokka < Yliluokka
  @@count = 0  # Luokkamuuttujan alustus

  def initialize(x)  # Konstruktori
    @x = x        # Sijoitus jäsenmuuttujaan
    @@count += 1  # Sijoitus luokkamuuttujaan
  end

  # Jäsenmetodi
  def jmetodi(a, b, c)
    a*x*x + b*x + c
  end

  # Luokkametodi
  def Luokka.lmetodi
    "Minusta on luotu " + @@count.to_s + " ilmentymää"
  end

  # Aksessoreja
  def x
    @x
  end
  def x=(new_x)
    @x = new_x
  end

  # Korvattu metodi
  def yliluokan_metodi(x)
    puts "yliluokan_metodia_kutsuttu"
    super  # Välittää parametrin implisiittisesti
  end
end

Muuttujien näkyvyysalueet

Jokainen luokka on luokan Class ilmentymä. Koska jokainen luokka on olio, voi luokillakin olla jäsenmuuttujia (instance variable, @). Nämä ovat kuitenkin eri asia kuin luokkamuuttujat (class variable, @@).

Luokkamuuttujat näkyvät sekä luokassa että sen olioissa.
Luokan jäsenmuuttujat ovat suoraan käytettävissä vain luokkametodeissa.
Olion jäsenmuuttujat ovat suoraan käytettävissä vain olion metodeissa.
Seuraava esimerkki selventänee tilannetta:

class Luokka
  @@foo = 1  # Luokkamuuttuja
  @foo = 2   # Luokan jäsenmuuttuja
  def initialize
    @foo = 3 # Olion jäsenmuuttuja
  end

  def printtaa
    puts @@foo.to_s  # => 1

    puts self.class.instance_variable_get(:@foo)  # => 2

    puts @foo.to_s  # => 3
    puts self.instance_variable_get(:@foo)  # => 3
  end

  def Luokka.printtaa
    puts @@foo.to_s  # => 1
    puts @foo.to_s  # => 2
  end
end

Luokka.new.printtaa
puts
Luokka.printtaa

Ilmentymäluokka

Jokaisella oliolla (paitsi välittömillä arvoilla) voi olla oma ilmentymäluokkansa (eigenclass, singleton class). Ilmentymäluokka on oliokohtainen perintähierarkian loppuun lisättävä luokka, jossa voidaan määrittää oliokohtaista toiminnallisuutta.
Esimerkki:

a = Object.new
b = Object.new
class << a
  def foo; puts "Olen vain a:ssa"; end
end
a.foo
b.foo  # Virhe

Luokkakonteksti

Kaikki Ruby-koodi on jonkin luokan (tai moduulin) kontekstissa. Myös tulkin päätasolle kirjoitettu koodi menee itse asiassa Object-luokan kontekstiin. Näin ollen seuraavanlainenkin koodi on aivan mahdollinen, vaikkakin typerä:

require 'time'

class LaiskaLuokka
  if Time.new.wday == 0
    puts "En tee töitä sunnuntaisin"
  else
    def Luokka.tervehdi
      puts "Tervehdys vuodelta #{Time.new.year}"
    end
  end
end

begin
  Luokka.tervehdi
rescue NoMethodError => e
  puts "Virhe: Luokalla ei ole luokkametodia 'tervehdi'."
end

Samanlaista temppuilua voisi harrastaa myös yksittäisten olioiden ilmentymäluokissa.

Luokkakontekstin voi myös avata uudelleen missä kohdassa koodia tahansa.

# Integer on Rubyn sisäinen yliluokka kaikille kokonaisluvuille (Fixnum ja Bignum)
class Integer
  def prime?
    if self == 2 or self == 3
      true
    elsif self < 2
      false
    else
      ( (2..(self/2)).find {|x| self % x == 0} ) == nil
    end
  end
end

p (1..100).select {|x| x.prime?}  # Hidasta mutta kaunista

if 1 + 1 == 2
  class Integer
    def in_range?(r)
      r.include? self
    end
  end
end

123.in_range? 1..1000  # => true

Lisää luokkien määrittelystä

Triviaalien aksessorimetodien kirjoittaminen on tylsää, sen tietää varsinkin jokainen Javalla ohjelmoinut. Ruby tarjoaa tähän apuvälineitä, nimittäin metodit attr_reader, attr_writer ja attr_accessor:

class Luokka
  attr_reader :a, :b, :c
  attr_writer :vain_kirjoitus
  attr_accessor :x, :y, :z

  def initialize
    @a = 1; @b = 2; @c = 3  # Näitä voi vain lukea
    @vain_kirjoitus = 13  # Tälle generoitiin vain kirjoitusaksessori
    @x = 10; @y = 100; @z = 1000  # Tälle luotiin sekä luku- että kirjoitusaksessorit
  end
end

Kyseiset metodit on toteutettu Rubyn ytimessä C-kielellä C:n nopeusedun takia, mutta ne voitaisiin yhtä hyvin kirjoittaa Rubylla käyttämällä esimerkiksi class_eval-rakennetta (ks. Metaprogramming Ruby [pdf]).

Näkyvyyden säätely: public, private, protected

public-määreellä merkityt metodit ovat kaikkien käytettävissä (tämä on oletusarvo).
private tarkoittaa, että vain kyseinen olio voi käyttää metodia (toisen samantyyppisen olion metodiin ei ole pääsyä).
protected antaa pääsyn toisille saman luokan tai siitä perityn luokan edustajille.

Näkyvyydensäätelymääreitä voidaan kirjoittaa kahdella tavalla: joko listaamalla symboleilla metodeja, joille määre pätee, tai kirjoittamalla määreen avainsana jollekin riville yksin, jolloin määre on voimassa siitä kohdasta eteenpäin.

class Visibilities
  def privaatti
  end
  def privaatti2
  end

  private :privaatti, :privaatti2

protected
  def tasta_eteenpain_kaikki_protectedeja
  end
end

Moduulit

Moduulit ovat metodikokoelmia. Niitä voidaan käyttää nimiavaruuksina (esim. Math-moduuli) tai mixin-luokkina.

Moduulin määrittely

module OddEven
  def OddEven.odd?(x)  # kirjastometodi; vrt. luokkametodi
    x % 2 == 1
  end
  def OddEven.even?(x)
    x % 2 == 0
  end
end

OddEven.odd? 123  # => true

Moduuli mixin-luokkana

Moduuliin voidaan kirjoitaa myös ilmentymämetodeja, joita voidaan liittää luokkiin (tai toisiin moduuleihin) include-avainsanalla.

module Odd
  def odd?
    self % 2 == 1
  end
end

module OddEven
  include Odd  # Moduuli voidaan liittää toiseen moduuliin
  def even?
    self % 2 == 0
  end
end

class Integer
  include OddEven  # Moduulin liittäminen luokkaan
end

123.odd?  # => true

Moduulin liittäminen korvaa luokassa tai moduulissa olevat samannimiset metodit.

Moduulin voi yhtä hyvin liittää yksittäisten olioiden ilmentymäluokkiin.

module OnlyWhiteSpace
  def only_whitespace?
    self.strip.empty?
  end
end

a = "     "
b = "   42"
c = "     "

class << a
  include OnlyWhiteSpace
end

b.extend OnlyWhiteSpace  # Vaihtoehtoinen tapa

a.only_whitespace?  # => true
b.only_whitespace?  # => false
c.only_whitespace?  # => virhe

Moduulin poistamiseen luokasta ei ole mitään valmista keinoa. Ominaisuus on jätetty tarkoituksella kielestä pois liian ongelmallisena esimerkiksi perinnän yhteydessä.

Sekalaista

Poikkeukset

Poikkeuksia heitetään avainsanalla raise ja siepataan begin – end -lohkoissa rescue -ilmaisulla.

begin
  if not 123.respond_to? :even?
    raise NoMethodError.new("Haluan käyttää even?-metodia!")
  end
rescue NoMethodError => ex
  puts 'Tapahtui virhe. Järjestelmä sanoo: "' + ex.message + '"'
end

begin .. raise .. rescue on tarkoitettu virheiden käsittelyyn. raise:lla voidaan heittää vain Exception-luokasta periviä luokkia tai olioita (merkkijonoista tehdään RuntimeError-olioita).

Rubyssa on myös toinen vastaavanlainen rakenne, catch :sym { .. throw :sym arvo }, joka on tarkoitettu arvon palauttamiseen syvästä rekursiopinosta. throw ottaa parametrikseen symbolin ja palautettavan olion (oletuksena nil) ja palauttaa kontrollin ensimmäiselle vastaantulevalle catch-ilmaisulle, joka odottaa kyseistä symbolia.

def tee_jotain
  throw :valmis, 42
end
arvo = catch :valmis do
  tee_jotain
end
puts arvo.to_s  # => 42

Tätä epätyylikästä ilmaisua tarvitaan onneksi melko harvoin.

method_missing

method_missing on eräs voimakas metaohjelmoinnin väline. Jokaisella oliolla on metodi method_missing, jota kutsutaan aina, kun oliolle lähetetään kutsu metodille, jota oliolla ei ole. Oletuksena method_missing heitää NoMethodError-poikkeuksen.

class Integer
  def method_missing(metodi, *argumentit, &lohko)
    puts "Ei kokonaisluvuilla ole metodia #{metodi}!"
    super
  end
end
3.foo

Linkkejä