Ruby (programmeerimiskeel)

**Ruby** on interpreteeritav programmeerimiskeel, mille looja on Yukihiro Matsumoto. 

Ruby on dünaamiliselt tüübitud ja mälukoristusvahenditega keel, mis võimaldab kasutada mitmesuguseid programmeerimise paradigmasid, kaasa arvatud protseduraalset, objektorienteeritut ja funktsionaalset programmeerimist. Ruby loomisel võttis Matsumoto inspiratsiooni mitmest programmeerimiskeelest, näiteks Perlist, Smalltalkist, Adast, Eiffelist, BASICust ja Lispist.

Ruby teeke tuntakse nimetuse "gem" all ning programmi RubyGems abiga on neid võimalik lihtsasti käsurea kaudu installida.

## Ajalugu

Matsumoto mõtles Ruby välja aastal 1993 ning kirjeldab Rubyt kui keelt, mis on sisemuselt justkui Lisp, objektisüsteemiga nagu Smalltalk, plokkidega, mis võtavad inspiratsiooni kõrgemat järku funktsioonidelt ning Perli praktilise kasulikkusega.

Nimi Ruby pärineb 24. veebruaril 1993 toimunud veebivestlusest Matsumoto ja Keiju Ishitsuka vahel veel enne, kui Matsumoto oli keelt looma hakanud. Algul pakkusid nad välja kaks nime: Coral ja Ruby, millest Matsumoto valis viimase. Matsumoto on hiljem öelnud, et nimevalikus üks mängis rolli ühe tema kolleegi sünnikivi, milleks oli rubiin.

Esimene avalik Ruby versioon oli 0.95, mis tuli välja 21. detsembril 1995. Järgmise kahe päeva jooksul ilmus veel kolm uut Ruby versiooni. Selles faasis olid Rubys juba mitmed tuttavad funktsioonid, seehulgas peamiselt objektorienteeritud disain, klassid koos pärimisega, mikserid, iteraatorid, sulundid, eranditöötlus ja mälukoristusvahendid.

Esimene artikkel Ruby kohta kirjutati alles aastal 1997. Samal aastal värvati Matsumoto tööle ettevõttesse netlab.jp, et töötada Ruby kallal täiskohaga arendajana. 1998. aastal lõi Matsumoto Ruby Application Archive'i ning esimese ingliskeelse veebilehe Ruby kohta. 1999. aastal loodi ka ingliskeelne Ruby postiloend kasvava huvi tõttu keele vastu väljaspool Jaapanit. 1999. aastal kirjutasid Matsumoto ja Keiju Ishitsuka Ruby kohta raamatu "Objektorienteeritud skriptimiskeel Ruby" (*オブジェクト指向スクリプト言語 Ruby*), mis avaldati Jaapanis 1999. aasta oktoobris. 2000. aastate alguses kirjutati Ruby kohta Jaapanis veel paarkümmend raamatut.

2000. aastaks oli Ruby Jaapanis populaarsem kui Python. 2000. aasta septembris ilmus Ruby kohta ka ingliskeelne raamat "Programming Ruby", mis avaldati hiljem internetis tasuta, mis suurendas huvi Ruby kohta väljaspool Jaapanit veelgi rohkem. 2002. aasta alguseks oli ingliskeelne Ruby postiloend tunduvalt populaarsem kui jaapanikeelne, demonstreerides Ruby kasutuse kasvu mujal maailmas.

### Varased Ruby versioonid
Pärast Ruby versiooni 0.95 1995. aastal anti välja veel mitu stabiilset Ruby versiooni:
*Ruby 1.0 – 25. detsember 1996
*Ruby 1.2 – 1998. aasta detsember
*Ruby 1.4 – 1999. aasta august
*Ruby 1.6 – 2000. aasta september

### Ruby 1.8
Ruby versioon 1.8 ilmus algselt 2003. aasta augustis ning oli pikka aega Ruby stabiilne versioon. Ruby 1.8 määratleti aegunud versioonina alles 2013. aasta juunis. Sellest hoolimata leiab veel palju koodi, mis on kirjutatud just selles versioonis. Ruby versioonil 1.8 kirjutati algne versioon veebiraamistikust Ruby on Rails, mis aitas muuta Ruby veelgi populaarsemaks.

### Ruby 1.9
Ruby versioon 1.9 ilmus algselt 25. detsembril 2007. Versioon 1.9 erines päris palju varasematest versioonidest ning seetõttu võttis aega, et 1.9 omaks võetaks, kuna see nõudis suure osa koodi ümberkirjutamist ning ka kolmandate osapoolte kirjutatud gemide uuendamist.

Ruby 1.9 tõi keelde suuri muudatusi, näiteks:
*lokaalsed muutujad
*uue lambda süntaksi: 
*uue paisktabeli süntaksi: 
*igale sõnele spetsiifilise tähemärgikodeeringu andmise võimaluse
*uue võrgusokli rakendusliidese (koos toetusega IPv6le)
* importide turvalisuse

Ruby 1.9 määratleti aegunud versioonina 23. veebruaril 2015.

### Ruby 2.0
Ruby versioon 2.0 ilmus 24. veebruaril 2013. Peaaegu kogu Ruby 1.9 kood sobitub automaatselt Ruby versiooniga 2.0, esineda võib vaid üksikuid probleeme.

Ruby 2.0 tõi keelde veelgi muudatusi, näiteks:
*meetoditele võtmesõnade argumendid
*meetodi  klasside laiendamiseks
*konstandi, mis sisaldab järjendit sümbolitest
*uue tava kasutada meetodit  et muuta objektid paisktabeliteks

Ruby 2.0 määratleti aegunud versioonina 22. veebruaril 2016.

### Ruby 2.1
Ruby versioon 2.1.0 ilmus 25. detsembril 2013. See versioon aitas kaasa keele optimeerimisele ning parandas mõningaid vigu.

Ruby 2.1 määratleti aegunud versioonina 1. aprillil 2017, viimane versiooninumber oli 2.1.10.

### Ruby 2.2
Ruby versioon 2.2.0 ilmus 25. detsembril 2014. Versioon optimeeris keelt veelgi ning parandas vigu, samuti uuendati teeke ning eemaldati mõningad aegunud rakendusliidesed. Suurimad muudatused Ruby 2.2.0 puhul on seostatud mäluga, näiteks on mälukoristusvahendid nüüd inkrementaalsed ning töötavad ka sümbolitega.

Ruby 2.2 määratleti aegunud versioonina 31. märtsil 2018, viimane versiooninumber oli 2.2.10.

### Ruby 2.3
Ruby versioon 2.3.0 ilmus 25. detsembril 2015. Mõned tähtsamad muudatused versioonis 2.3:
*sõneoperatsioone sõnekonstantide peal on võimalik muuta kiiremaks muutes sõnekonstandid hangunuks
*paisktabelite võrdlemisel on võimalik võrrelda võtmeid ja väärtusi korraga, varem sai korraga võrrelda ainult võtmeid 
*nagivatsioonioperaator , mis teeb nil väärtuste käitlemise lihtsamaks (näiteks  asemel saab kasutada 
**did_you_mean* gem on nüüd baaskoodis ning aitab automaatselt leida sarnaseid objektide nimesid *NameError*i või *NoMethodError*i puhul
*meetod  järjendite ja paisktabelite jaoks, mis aitavad kergemini saada andmestruktuuridest sügavamaid väärtusi (näiteks paisktabelist  saab väärtuse *Mari Mets* kätte kasutades koodi )

Versioon 2.3 aitab kaasa ka keele üleüldisele optimeerimisele ning parandab muid vigu.

Ruby 2.3 määratleti aegunud versioonina 31. märtsil 2019, viimane versiooninumber oli 2.3.8.

### Ruby 2.4
Ruby versioon 2.4.0 ilmus 25. detsembril 2016. Mõned tähtsaad muudatused versioonis 2.4:
**Fixnum* ja *Bignum* objektid on nüüd mõlemad klassifitseeritud osana *Integer* klassist, ehk täisarvudena
*uus meetod , mis on kiirem versioon meetodist  ning tagastab tõeväärtuse

Ruby 2.4 on jätkuvalt toetatud versioon ning viimane versiooninumber on 2.4.8, kuid määratletakse kui aegunud versioon 1. aprillil 2020. 

### Ruby 2.5
Ruby versioon 2.5.0 ilmus 25. detsembril 2017. Mõned tähtsamad muudatused versioonis 2.5:
**rescue* ja *ensure* laused kasutavad nüüd automaatselt *do-end* plokki
*paisktabelite muutmiseks meetodid  ja 

Versioon 2.5 toob kaasa ka palju parandusi keele optimeerimiseks, näiteks plokkide läbimine on 3 korda kiirem ning mõned objektide liitmismeetodid on samuti kiiremad.

Ruby 2.5 on jätkuvalt toetatud versioon ning viimane versiooninumber on 2.5.7. 

### Ruby 2.6
Ruby versioon 2.6.0 ilmus 25. detsembril 2018. Ruby 2.6 on jätkuvalt toetatud versioon ning viimane versiooninumber on 2.6.5.

### Ruby 2.7
Ruby versioon 2.7.0 ilmus 25. detsembril 2019. Ruby 2.7 on hetkene stabiilne versioon ning viimane versiooninumber on 2.7.0.

## Näited
Klassikaline Hello world programm:

```ruby
puts 'Hello World!'
```


Rubys käsitletakse kõiki andmetüüpe (sealhulgas täisarve ja tõeväärtusi) objektidena, seega:

```ruby
-199.abs                                                 # => 199
'ruby on lahe'.length                                    # => 12
'ruby on lahe'.index('u')                                # => 1
"Kena, kas pole?".downcase.split('').uniq.sort.join      # => " ,?aeklnops"
```


Sisendid:

```ruby
print 'Palun sisesta oma nimi:'
nimi = gets.chomp
puts "Tere, #{nimi}."
```


Konversioonid:

```ruby
puts 'Anna mulle arv:'
arv = gets.chomp
puts arv.to_i
arv_välja = arv.to_i + 1
puts arv_välja.to_s + ' on suurem arv.'
```


### Sõned
Rubys on sõnesid võimalik defineerida mitmel viisil. Järgnevad muutujad on sama väärtusega:

```ruby
a = "\nSee on jutumärkides sõne\n"
b = %Q{\nSee on jutumärkides sõne\n}
c = %{\nSee on jutumärkides sõne\n}
d = %/\nSee on jutumärkides sõne\n/
e = <<-BLOCK

See on jutumärkides sõne
BLOCK
```


Sõnedes saab muutujaid interpoleerida:

```ruby
var = 3.14159
"pi on #{var}"
=> "pi on 3.14159"
```


Sõnekonstante saab defineerida järgnevalt:

```ruby
a = 'See on ülakomades sõne'
a = %q{See on ülakomades sõne}
```


### Andmestruktuurid
Rubys on kasutusel mitmed andmestruktuurid.

Järjendite kasutamine käib järgmiselt:

```ruby
a = [1, 'hi', 3.14, 1, 2, [4, 5]]

a[2]             # => 3.14
a.[](2)          # => 3.14
a.reverse        # => [[4, 5], 2, 1, 3.14, 'hi', 1]
a.flatten.uniq   # => [1, 'hi', 3.14, 2, 4, 5]
```


Rubys on olemas ka sõnastiku tüüpi andmestruktuur, mida nimetatakse paisktabeliks (inglise keeles *hash*)

```ruby
hash = Hash.new                               # samaväärne kui hash = {}
hash = { :vesi => 'märg', :tuli => 'kuum' }   # defineerib hash objekti ümber
puts hash[:tuli]                              # prindib ekraanile "kuum"

hash.each_pair do |key, value|                # või ka: hash.each do |key, value|
  puts "#{key} on #{value}"
end
# tagastab {:vesti =>"märg", :tuli=>"kuum"} ja prindib:
# vesi on märg
# tuli on kuum

hash.delete :vesi                             # kustutab paari :vesi => 'märg' ja tagastab "märg"
hash.delete_if {|key,value| value == 'kuum'}  # kustutab paari :tuli => 'kuum' ja tagastab {}
```


### Tingimuslaused
If-lause:

```ruby
# Genereerib suvalise arvu ning prindib välja kas tegemist on paaris- või paaritu arvuga
if rand(100).even?
  puts "Paaris"
else
  puts "Paaritu"
end
```


### Plokid ja korduslaused
Rubys on kaks süntaksit koodiplokkide loomiseks:

```ruby
{ puts 'Hello, World!' }
# või:
do
  puts 'Hello, World!'
end
```


Koodiploki saab anda meetodile argumendiks. Paljud meetodid kasutavad neid argumente:

```ruby
File.open('fail.txt', 'w') do |fail|
  fail.puts 'Kirjutasin midagi.'
end # fail suletakse automaatselt

File.readlines('fail.txt').each do |rida|
  puts rida
end
# => Kirjutasin midagi.
```


Anonüümsed funktsioonid:

```ruby
proc {|arg| puts arg}
Proc.new {|arg| puts arg}
lambda {|arg| puts arg}
->(arg) {puts arg}         # alates Ruby versioonist 1.9
```


Korduslaused vahemike ja järjendite puhul kasutavad plokke:

```ruby
järjend = [1, 'hi', 3.14]
järjend.each {|item| puts item }
# prindib:
# 1
# 'hi'
# 3.14

järjend.each_index {|index| puts "#{index}: #{array[index]}" }
# prindib:
# 0: 1
# 1: 'hi'
# 2: 3.14

# (a..b) vahemik
(3..6).each {|num| puts num }
# prindib:
# 3
# 4
# 5
# 6

# (a...b) vahemik
(3...6).each {|num| puts num }
# prindib:
# 3
# 4
# 5
```


### Klassid
Järgnev kood defineerib klassi nimega `Inimene`. Lisaks `initialize` meetodile, millega klass konstrueeritakse, on sellel veel kaks meetodit: üks, mis kirjutab üle võrdlusoperaatori  (nii, et  saab sorteerida vanuse järgi) ja teine, mis kirjutab üle  meetodi (nii, et  saab väljundit vormindada).  on Ruby metaprogrammeerimise näide:  defineerib nii getteri kui ka setteri meetodid, kuid  defineerib ainult getter meetodi. Viimane lause meetodis on väärtus mille see väljastab, seega ei ole vaja defineerida `return` lauset.


```ruby
class Inimene
  attr_reader :nimi, :vanus
  def initialize(nimi, vanus)
    @nimi, @vanus = nimi, vanus
  end
  def <=>(person) # võrdlusoperaator sorteerimiseks
    @vanus <=> person.vanus
  end
  def to_s
    "#{@nimi} (#{@vanus})"
  end
end

grupp = [
  Inimene.new("Mari", 33),
  Inimene.new("Marina", 16),
  Inimene.new("Martina", 23)
]

puts grupp.sort.reverse

# prindib:
# Mari (33)
# Martina (23)
# Marina (16)
```


`Inimene` on siin konstant ja viitab `Class` objektile.

### Erindid
Erindeid saab tekitada `raise` lause abil:

```ruby
raise
```


Erindile saab juurde lisada ka mingi sõnumi:

```ruby
raise "See on sõnum"
```


Võimalik on defineerida ka erindi tüüpi:

```ruby
raise ArgumentError, "Mittesobivad argumendid!"
# või ka
# raise ArgumentError.new("Mittesobivad argumendid!")
```


Erindeid käsitletakse `rescue` lausega. See lause püüab kõiki erindeid, mis pärinevad `StandardError` klassist. Erindite püüdmisel saab kasutada ka `else` ja `ensure` lauseid:

```ruby
begin
  # tee midagi
rescue
  # käsitle erindit
else
  # tee seda juhul kui erindit ei tekkinud
ensure
  # tee seda, vahet pole kas tekkis erind või mitte
end
```


`StandardError` ja `Exception` on Rubys eraldi klassid, `StandardError` pärineb `Exception`ist, kuid kuna `rescue` käsitleb vaid erindeid, mis pärinevad `StandardError` klassist, ei pruugi ta alati kinni püüda kõiki erindeid. Selleks peab eraldi defineerima:

```ruby
begin
  # tee midagi
rescue Exception
  # käsitle erindit 
end
```


Või kinni püüdma mõne kindla erindi:

```ruby
begin
  # tee midagi
rescue RuntimeError
  # käsitle ainult RuntimeErrorit ja kõiki teisi sellest pärinevaid erindeid
end
```


Erindi objekti saab kätte sedasi:

```ruby
begin
  # tee midagi
rescue RuntimeError => e
  # käsitle RuntimeErrorit ning tee midagi muutujaga e, näiteks
  puts e.to_s
end
```


## Vaata ka
* Ruby on Rails

## Viited

## Välislingid
* Rubytogether
* Rubigems